6.2 实现Nginx TCP负载均衡
Nginx在1.9.0版本开始支持tcp模式的负载均衡, 在1.9.13版本开始支持udp协议的负载均衡, udp主要用于DNS的域名解析, 其配置方式和指令和http代理类似, 其基于ngx_stream_proxy_module模块实现tcp负载, 另外基于模块ngx_http_upstream_module实现后端服务器分组转发, 权重分配, 状态监测, 调度算法等高级功能
如果是编译安装, 需要指定--with-stream选项才能支持ngx_stream_proxy_module模块
6.2.1 tcp 负载均衡配置参数
stream { # 定义stream相关的服务, 定义在main语句块和http平级
upstream backend { # 定义后端服务器
hash $remote_addr consistent; # 定义调度算法
server backend1.example.com:12345 weight=5; # 定义具体server
server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
upstream dns { # 定义后端服务器
server 10.0.0.1:53535; # 定义具体server
server dns.example.com:53;
}
server { # 定义server, 定义nginx如何接收和转发远程用户的请求
listen 12345; # 监听ip:port
proxy_connect_timeout 1s; # 连接超时时间
proxy_timeout 3s; # 转发超时时间
proxy_pass backend; # 转发到具体服务器组
}
server {
listen 127.0.0.1:53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns;
}
server {
listen [::1]:12345;
proxy_pass unix:/tmp/stream.socket;
}
}
6.2.2 负载均衡案例: Redis
6.2.2.1 准备环境
准备两台后端服务器, 安装redis
可以基于每台服务器的run_id测试调度结果
yum -y install redis
vim /etc/redis.conf
bind 0.0.0.0
systemctl enable --now redis
6.2.2.2 nginx配置负载均衡
# 先在nginx主配置文件定义tcp负载均衡的子配置文件路径
[13:50:26 root@nginx ~]#vim /apps/nginx/conf/nginx.conf
include /apps/nginx/conf/tcp/tcp.conf; # 注意: tcp负载均衡的子配置文件路径指令要和http语句块平级, 一般写在主配置文件最后即可, 由于stream是一级语句块, 整个nginx只能有一个, 因此, 所有的tcp/udp负载均衡配置, 都写在同一个文件里
[00:30:17 root@nginx /apps/nginx/conf/tcp]#vim redis.conf
stream {
upstream redis-server {
server 10.0.0.85:6379 weight=2;
server 10.0.0.84:6379 weight=1;
}
server{
# 配置负载均衡时, server语句块不支持server_name, 客户端直接访问nginx的ip地址和端口
listen 6379;
proxy_pass redis-server;
}
}
[00:35:51 root@nginx /apps/nginx/conf/tcp]#nginx -s reload
[13:51:16 root@nginx ~]#ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:6379 # 验证监听6379端口 0.0.0.0:*
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
6.2.2.3 客户端连接nginx测试
# 可以看到1:2调度
[00:38:02 root@client ~]#redis-cli -h 10.0.0.86 info server | grep run_id
run_id:6c86d33bf1002c7839f43a6ac9055f0406d61b7a
[00:38:25 root@client ~]#redis-cli -h 10.0.0.86 info server | grep run_id
run_id:580343970ae2d5078ff064260e170a8932a48338
[00:38:27 root@client ~]#redis-cli -h 10.0.0.86 info server | grep run_id
run_id:6c86d33bf1002c7839f43a6ac9055f0406d61b7a
[00:38:28 root@client ~]#redis-cli -h 10.0.0.86 info server | grep run_id
run_id:6c86d33bf1002c7839f43a6ac9055f0406d61b7a
6.2.3 负载均衡案例: MySQL
6.2.3.1 准备环境
为了测试效果, 后端分别使用mariadb和mysql
数据库上创建用户, 需要对nginx的ip地址进行授权
nginx基于四层的调度是伪四层, 因此nginx会拆分请求和响应报文, 重新封装
# 10.0.0.85 - MySQL
[23:34:16 root@mysql ~]#yum -y install mysql-server
[23:35:30 root@mysql ~]#systemctl enable --now mysqld
Created symlink /etc/systemd/system/multi-user.target.wants/mysqld.service → /usr/lib/systemd/system/mysqld.service.
[23:42:31 root@mysql ~]#mysql -e 'create user admin@"10.0.0.%" identified by "000000"'
# 10.0.0.84 - MariaDB
[23:34:41 root@mariadb ~]#yum -y install mariadb-server
[23:35:13 root@mariadb ~]#systemctl enable --now mariadb
Created symlink /etc/systemd/system/mysql.service → /usr/lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/mysqld.service → /usr/lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/multi-user.target.wants/mariadb.service → /usr/lib/systemd/system/mariadb.service.
[23:44:03 root@mariadb ~]#mysql -e 'create user admin@"10.0.0.%" identified by "000000"'
6.2.3.2 nginx配置负载均衡
# 单独指定存放tcp负载均衡的配置文件, 关于tcp的负载均衡配置, 都可以写到tcp目录下某个.conf文件里, 因为stream是一级语句块, 一个服务器只能有一个, 因此只能存在一个.conf配置文件, 专门来配置tcp负载均衡, 如果多个文件都有stream模块, 那么重启nginx会报错
include /apps/nginx/conf/tcp/*.conf;
[23:47:05 root@nginx /apps/nginx/conf]#mkdir /apps/nginx/conf/tcp
[23:47:44 root@nginx /apps/nginx/conf]#cd /apps/nginx/conf/tcp
[23:47:45 root@nginx /apps/nginx/conf/tcp]#
[23:47:46 root@nginx /apps/nginx/conf/tcp]#
[23:47:46 root@nginx /apps/nginx/conf/tcp]#vim mysql.conf
[23:47:46 root@nginx /apps/nginx/conf/tcp]#vim mysql.conf
stream {
upstream mysql-server { # upstream定义后端服务器组
server 10.0.0.85:3306 max_fails=3 fail_timeout=30s;
server 10.0.0.84:3306; # 后端服务器监听的端口
}
server { # server定义nginx如何接收和处理客户端请求, 包括监听的端口, 和转发到的后端群组
listen 3306; # 面对客户端的端口
proxy_pass mysql-server;
}
}
[23:59:02 root@nginx /apps/nginx/conf/tcp]#nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[23:59:05 root@nginx /apps/nginx/conf/tcp]#nginx -s reload
[23:59:10 root@nginx /apps/nginx/conf/tcp]#ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:3306 0.0.0.0:*
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
6.2.3.3 客户端连接nginx测试
# 10.0.0.187安装mysql客户端
[00:00:27 root@client ~]#yum -y install mysql
# 连接nginx
[00:00:44 root@client ~]#mysql -h 10.0.0.86 -uadmin -p000000
MySQL [(none)]>
# 验证版本
此时后端服务器会认为是nginx在访问, 因此数据库授权也是针对nginx进行授权
通过nginx的tcp负载均衡, 可以实现对后端的PXC集群进行调度
补充: lvs和nginx四层负载均衡的区别
nginx对于tcp的负载均衡实际是伪四层, 因为nginx会代替客户端向后端服务器发起请求, 而不是单独的转发, 后端服务器看到的是nginx服务器的ip地址
lvs对于tcp的负载均衡是只转发, 后端服务器看到的是客户端的源ip地址