Nginx+Consul+UpSync动态配置负载均衡(二)

  • 一、安装nginx模块
  • 1.合并module
  • 2.重新编译nginx
  • 二、添加stream配置文件
  • 1.添加stream模块
  • 2.创建stream配置文件
  • 3.创建持久化文件目录
  • 4.启动nginx
  • 三、模拟tcp服务端
  • 1.创建tcp服务器
  • 2.给每个服务做区分
  • 四、开启并验证tcp的动态负载均衡
  • 1.启动Consul服务
  • 2.添加服务端信息到consul
  • 3.验证动态负载均衡是否成功
  • 五、问题记录
  • 1. upsync_del_peer: upstream "app" cannot delete all peers
  • 2. upsync_check_key: has no port in /



环境说明

主机名

系统版本

ip地址

nginx version

consul version

upsync version

备注

master

centos-release-7-7.1908.0.el7.centos.x86_64

192.168.137.252

nginx-1.17.5

consul_1.6.1_linux_amd64

nginx-upsync-module

上一篇我们使用Consul+UpSync的方案给ngxin加上了动态负载均衡的功能,但是他只能作为http模块中的负载均衡,也就是只能代理http协议。这篇,在之前的基础上,我们加强一下,添加一个支持stream模块的动态负载均衡功能,让nginx支持tcp/udp的动态负载。顺便也温习一下其他知识点。

一、安装nginx模块

之前我们已经下载过nginx-upsync-module模块了,但是这个模块不支持在stream{}模块中使用,而nginx-stream-upsync-module模块是为stream{}提供支持的。我们需要同时安装这两个module模块。但是想要同时使用这两个模块的话,是不能同时在编译nginx的时候把这两个模块一起编译进去的。所以我们需要先将两个模块合并成一个。

1.合并module

[root@master02 ~]# cd /opt/nginx/
[root@master02 nginx]# git clone https://github.com/CallMeFoxie/nginx-upsync.git

原文章是将3个资源包下载好之后再进行复制的,但是他那里写的复制命令是有问题的,不能复制子目录,请注意。
我们这里直接进行下载覆盖即可。

[root@master02 nginx]# cd /opt/nginx/nginx-upsync
[root@master02 nginx-upsync]# git clone https://github.com/weibocom/nginx-upsync-module.git
[root@master02 nginx-upsync]# git clone https://github.com/xiaokai-wang/nginx-stream-upsync-module.git

这样我们就将nginx-upsync-modulenginx-stream-upsync-module两个模块合并成了nginx-upsync模块了。

2.重新编译nginx

之前我们已经编译过一次nginx了,但是当时只将nginx-upsync-module模块编译进去,现在我们需要用nginx-upsync模块进行替换,所以要重新编译。
2.1 编译安装nginx

[root@master02 nginx-upsync]# cd /opt/nginx/nginx-1.17.5
[root@master02 nginx-1.17.5]# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_flv_module --with-http_stub_status_module --with-http_gzip_static_module --with-http_realip_module --with-pcre --add-module=/opt/nginx/nginx-upsync --with-stream

注意最后两个参数--add-module=/opt/nginx/nginx-upsync --with-stream,第一个参数我们将之前的nginx-upsync-module替换成了nginx-upsync,第二个参数--with-stream是开启nginx的stream模块。

[root@master02 nginx-1.17.5]# make
[root@master02 nginx-1.17.5]# /usr/local/nginx/sbin/nginx -s stop
[root@master02 nginx-1.17.5]# \cp /opt/nginx/nginx-1.17.5/objs/nginx /usr/local/nginx/sbin/

第一条命令是安装,不要使用make install命令,这个命令可能会覆盖之前的nginx工作目录。
第二条命令是停止运行中的nginx,因为接下来我们要替换旧的nginx执行文件。
第三条是用刚刚编译安装成功的nginx替换旧的nginx执行文件。\cp命令的作用是若文件存在不询问直接覆盖。

我们可以使用-V命令来查看nginx的编译参数:

[root@master02 nginx-1.17.5]# /usr/local/nginx/sbin/nginx -V

nginx upstream 不替换 nginx upsync module_nginx


可以看到是我们刚刚的编译参数。

二、添加stream配置文件

1.添加stream模块

[root@master02 nginx-1.17.5]# cd /usr/local/nginx/conf
[root@master02 conf]# vim nginx.conf

在文件中添加如下代码块,stream模块与http模块并列。

stream {
    #加载外部配置文件
    include /usr/local/nginx/conf.d/stream/*.conf;
}

nginx upstream 不替换 nginx upsync module_nginx tcp 负载均衡_02

2.创建stream配置文件

[root@master02 conf]# mkdir /usr/local/nginx/conf.d/stream
[root@master02 conf]# cd /usr/local/nginx/conf.d/stream
[root@master02 stream]# vim stream-mysql-3307.conf

因为mysql通常是用tcp连接的,所以我们使用mysql来做测试。故文件名中有mysql。
文件中填入下面代码:

upstream mysql {
        server 127.0.0.1:11111;
        upsync 192.168.137.252:8500/v1/kv/upstreams/stream/ upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
        upsync_dump_path /usr/local/nginx/conf/servers/servers_stream.conf;
        include /usr/local/nginx/conf/servers/servers_stream.conf;
}

server {
        listen 3307;
        proxy_pass mysql;
}

nginx upstream 不替换 nginx upsync module_nginx stream动态负载均衡_03

3.创建持久化文件目录

[root@master02 stream]# vim /usr/local/nginx/conf/servers/servers_stream.conf

直接空文件退出即可。

4.启动nginx

[root@master02 stream]# /usr/local/nginx/sbin/nginx -t
[root@master02 stream]# /usr/local/nginx/sbin/nginx

三、模拟tcp服务端

1.创建tcp服务器

我们需要几个tcp的服务端来验证我们的动态负载是否可用。

我这边是使用docker,在docker中创建了3个mysql的容器:

nginx upstream 不替换 nginx upsync module_nginx_04


如果没有其他更好的方式,也可以采取我这种。我这个mysql是装在另外一台机子192.168.137.123上面。

2.给每个服务做区分

分别登录3个数据库服务端,我们在每个数据库服务端中都创建一个叫test的数据库实例,然后分别在每个数据库实例中创建一张表,我们可以创建不同的表名来做为三台服务器之间的区分。当然也可以表名相同,然后利用表中数据不同来做区分。我这里使用表名区分,更加简单、直观。

nginx upstream 不替换 nginx upsync module_nginx upstream 不替换_05

四、开启并验证tcp的动态负载均衡

1.启动Consul服务

如果之前启动的没有关闭就可以不用再启动了。

[root@master02 stream]# /opt/nginx/consul agent -dev -ui -node=consul-dev -client=192.168.137.252

2.添加服务端信息到consul

我们依次将3个mysql服务端的地址添加到consul

[root@master02 stream]# curl -X PUT http://192.168.137.252:8500/v1/kv/upstreams/tcp/192.168.137.123:3301
[root@master02 stream]# curl -X PUT http://192.168.137.252:8500/v1/kv/upstreams/tcp/192.168.137.123:3302
[root@master02 stream]# curl -X PUT http://192.168.137.252:8500/v1/kv/upstreams/tcp/192.168.137.123:3303

此时我们可以查看一下持久化文件中的内容

[root@master02 stream]# cat /usr/local/nginx/conf/servers/servers_tcp.conf

nginx upstream 不替换 nginx upsync module_nginx tcp 负载均衡_06


如果是我们刚刚添加的三个服务端列表的话,就是成功了。

3.验证动态负载均衡是否成功

我们在之前的navicat软件中新建一个连接。

连接至我们之前配置的192.168.137.252:3307

先点击测试连接,如果不成功的话,需要先找下原因。我这边是没问题的。

nginx upstream 不替换 nginx upsync module_nginx stream动态负载均衡_07


我们打开刚刚创建的连接,进入表选项中,可以看到一个表名称,我现在看到的是t_lb2这张表。

nginx upstream 不替换 nginx upsync module_nginx upstream 不替换_08


然后我们将连接先关闭,然后再重新连接,看看表有没有变化。可以看到我这里已经变成t_lb1表了

nginx upstream 不替换 nginx upsync module_mysql_09


重复几次关闭连接再重新连接,看看表的变化,会发现表名称会在t_lb1/t_lb2/t_lb3三张表中随机出现,这刚刚好对应到我们一开始在mysql的三个服务端中分别创建的3张表。由此也就可以说明我们的tcp动态负载均衡已经成功了。

如果还不太确信的话,可以使用命令删除两个负载均衡服务,只留下一个,再次验证一下lb-upstream-mysql中表的名称是不是不会变化了。

[root@master02 stream]# curl -X DELETE http://127.0.0.1:8500/v1/kv/upstreams/tcp/192.168.137.123:3302
[root@master02 stream]# curl -X DELETE http://127.0.0.1:8500/v1/kv/upstreams/tcp/192.168.137.123:3303

这个时候,再去尝试重新连接lb-upstream-mysql,发现不管重连多少次,表中只会出现t_lb1这个表名称。

这样就可以完全确定我们已经配置好了。

五、问题记录

1. upsync_del_peer: upstream “app” cannot delete all peers

当nginx重启,consul后台与持久化文件中的服务器列表不统一时,nginx日志中将会报错:

upsync_del_peer: upstream "app" cannot delete all peers
upsync_process: upstream del peers failed

nginx upstream 不替换 nginx upsync module_nginx stream动态负载均衡_10


但是这个时候负载均衡还是依然可以访问的,只是持久化文件写入失败了。consul服务正常启用的时候,负载均衡列表以consul服务中的列表为准。

如果我们想要持久化文件被写入,就要在nginx重启之前,将持久化文件内的服务器列表手动配置成跟consul后台一致,然后再重启nginx。这样问题就得以解决了。

2. upsync_check_key: has no port in /

nginx中会一直报这个错upsync_check_key: has no port in /,原因是consul在添加键值的时候,默认会把我们添加的文件夹也当成一个键值对,而文件夹这个key是没有带端口的。所以nginx会报这个错。
但是nginx可以正常使用的。这个错误,暂时我也不知道怎么解决。

参考连接:https://github.com/CallMeFoxie/nginx-upsynchttps://github.com/xiaokai-wang/nginx-stream-upsync-module