NGINX之七----Nginx反向代理实现均衡负载及调度方法
http upstream配置参数:
ngx_http_upstream_module模块
将多个服务器定义成服务器组,而由proxy_pass, fastcgi_pass等指令进行引用
upstream name { ... }
定义后端服务器组,会引入一个新的上下文;
默认调度算法是rr(轮询调动算法):
Context: http upstream httpdsrvs { server ... server... ... }
server address [parameters];
#配置一个后端web服务器,配置在upstream内,至少要有一个server服务器配置。
server支持的parameters如下:
weight=number #设置权重,默认为1。 max_conns=number #给当前server设置最大活动链接数,默认为0表示没有限制。 max_fails=number #对后端服务器连续监测失败多少次就标记为不可用。 fail_timeout=time #对后端服务器的单次监测超时时间,默认为10秒。 backup #设置为备份服务器,当所有服务器不可用时将重新启用次服务器。 down #标记为down状态。 resolve #当server定义的是主机名的时候,当A记录发生变化会自动应用新IP而不用重启Nginx。
实现nginx反向代理调度功能:
A主机:192.168.37.27 nginx服务器
B主机:192.168.37.17 httpd服务器
C主机:192.168.37.37 httpd服务器
nginx服务器上配置文件:
1、修改nginx配置文件,关联后端httpd服务,进行调度。
[root@centos27site1]#vim /etc/nginx/nginx.conf upstream websrv{ server 192.168.37.17:80; server 192.168.37.37:80; }
vim /etc/nginx/conf.d/test.conf
server { listen 80; server_name www.magedu.net; root /data/site1; index index.html; location / { proxy_pass http://websrv; } }
在两个后端httpd后端服务创建文件
[root@centos17~]#echo 192.168.37.17 > /var/www/html/index.html [root@centos17~]#systemctl start httpd [root@centos37site1]#systemctl start httpd [root@centos37site1]#echo 192.168.37.37 > /var/www/html/index.html
在客户端进行调度测试
[root@centos7~]#while true;do curl www.magedu.net;sleep 0.5;done 192.168.37.17 192.168.37.37 192.168.37.17 192.168.37.37 192.168.37.17
实现宕机功能:
修改nginx主配置文件即可,在监听的80端口后面加上down,就会将此服务器进行宕机:vim /etc/nginx/nginx.conf
http { upstream websrv{ server 192.168.37.17:80; server 192.168.37.37:80 down; 加入down,就会将此主机进行宕机处理。 }
在客户端进行测试效果,此时nginx很巧妙的只调度17的主机,不会在显示37宕机的效果,可以对后端服务器进行健康检查。
[root@centos7~]#while true;do curl www.magedu.net;sleep 0.5;done 192.168.37.17 192.168.37.17 192.168.37.17
实现道歉功能:
将nginx服务器端的配置文件进行修改:vim /etc/nginx/nginx.conf,80端口被占用,最好不要指定80端口。
upstream websrv{ server 192.168.37.17:80; server 192.168.37.37:80; server 127.0.0.1:8080 backup; }
在vim /etc/nginx/conf.d/test.conf配置文件中修改配置文件,当后端httpd都宕机之后,就会显示/data/site2里边的文件,作为道歉显示。
server { listen 8080; #server_name www.magedu.org; root /data/site2/; ssl_certificate /etc/nginx/ssl/magedu.org.crt; ssl_certificate_key /etc/nginx/ssl/magedu.org.key; ssl_session_cache shared:sslcache:20m; ssl_session_timeout 10m; access_log /var/log/nginx/magedu_org.access_json.log main; valid_referers none block server_names *.magedu.com ~\.google\. ~\.baidu\.; if ($invalid_referer) { return 403 "Forbidden Access"; } }
在nginx服务端的data/site2目录下新建一个html文件。
[root@centos27site1]#mkdir /data/site2 [root@centos27site1]#echo /data/site2/test.html > /data/site2/index.html
将httpd两个后端服务都停掉。
[root@centos37site1]#systemctl stop httpd
在客户端进行测试效果,由于后端服务器都宕机,此时就会显示nginx宕机道歉的文件信息。
[root@centos7~]#while true;do curl www.magedu.net;sleep 0.5;done /data/site2/test.html /data/site2/test.html
调度算法
ip_hash 源地址hash调度方法,基于的客户端的remote_addr(源地址)做hash计算,以实现会话保持。 least_conn 最少连接调度算法,当server拥有不同的权重时其为wlc,当所有后端主机连接数相同时,则使用wrr,适用于长连接,调度到最少连接的后端服务器上。 hash key [consistent] 基于指定的key的hash表来实现对请求的调度,此处的key可以直接文本、变量或二者组合。 作用:将请求分类,同一类请求将发往同一个upstream server,使用consistent参数,将使用ketama一致性hash算法,适用于后端是Cache服务器(如varnish)时使用。所谓取模运算,就是计算两个数相除之后的余数,比如10%7=3, 7%4=3 hash $request_uri consistent; #基于用户请求的uri做hash,一致性hash算法 hash $remote_addr; hash $cookie_name; #key为name的cookie keepalive 连接数N; 为每个worker进程保留的空闲的长连接数量,可节约nginx端口,并减少连接管理的消耗
一致性hash算法
原理:对于下图来看,节点数越少,越容易出现节点在哈希环上的分布不均匀,导致各节点映射的对象数量严重不均衡(数据倾斜);相反,节点数越多越密集,数据在哈希环上的分布就越均匀。
设计哈希函数 Hash(key),要求取值范围为 [0, 2^32)
在对IP地址进行hash运算的结果进行取模(2^32),针对每个全服务器的权重不同,都将IP地址进行hash算法运算,然后进行取模(2^32)。
原理诠释:
varnish 1(权重) hash(192.168.37.37)%2^32
varnish 2(权重) hash(192.168.37.47+random1)%2^32 hash(192.168.37.47+random2)%2^32 权重有两个,对IP地址进行两次hash运算。
varnish 3(权重) hash(192.168.37.57+random1)%2^32 hash(192.168.37.57+random2)%2^32 hash(192.168.37.57+random3)%2^32 权重有三个,就对IP地址进行三次hash运算。
以上展示,由于在hash环上只有六个随机环,有可能分部在一起,会导致分布不均匀,此时有可能就只有外部两个nginx服务器在工作,中间的四个环不会工作,造成两个环负荷过大。
解决办法:在保持权重占比的情况下,可以将三个varnish的权重分别乘以1000,如1*1000、2*1000、3*1000,此时相对的权重占比不变,环的数量增加,会将环的数量增加,不会导致数据倾斜现象,解决了不均匀的问题。
解决不均匀的代码:hash $request_uri consistent;
实现sessionid固定保证访问一个网址
1、在nginx服务器修改主配置文件
[root@centos27~]#vim /etc/nginx/nginx.conf upstream websrv{ server 192.168.37.17:80; server 192.168.37.37:80; hash $cookie_sessionid; }
在include指定的配置文件中添加要调用的后端httpd服务的IP地址。
[root@centos27~]#vim /etc/nginx/conf.d/test.conf server { listen 80; server_name www.magedu.net; root /data/site1; index index.html; location / { proxy_pass http://websrv; } }
2、在客户端进行测试验证效果,说明sessionid固定后,保证固定访问一个网址。
实现工作于传输层的反代理或调度器(用法不多)
ngx_stream_core_module模块
模拟反代基于tcp或udp的服务连接,即工作于传输层的反代或调度器
stream { ... }
定义stream相关的服务;Context:main
示例:
stream { upstream mysqlsrvs { server 192.168.8.2:3306; server 192.168.8.3:3306; least_conn; } server { listen 10.1.0.6:3306; proxy_pass mysqlsrvs; } }
各参数含义:
ngx_stream_proxy_module模块 可实现代理基于TCP,UDP (1.9.13), UNIX-domain sockets的数据流 proxy_pass address; 指定后端服务器地址 proxy_timeout timeout; 无数据传输时,保持连接状态的超时时长 默认为10m proxy_connect_timeout time; 设置nginx与被代理的服务器尝试建立连接的超时时长 默认为60s
1、在nginx服务器主配置文件中添加TCP和UDP协议。
[root@centos27~]#vim /etc/nginx/nginx.conf stream { upstream mysqlsrvs { server 192.168.37.17:3306; mysql1数据库 server 192.168.37.37:3306; mysql2数据库 least_conn; } server { listen 192.168.37.27:3306; nginx服务器 proxy_pass mysqlsrvs; } }
2、在两个mysql数据库创建相同用户账号及数据库,便于测试验证
[root@centos17~]#yum install mariadb-server [root@centos17~]#systemctl start mariadb [root@centos17~]#mysql -e "grant all on *.* to test@'192.168.37.%' identified by 'centos'" [root@centos17~]#mysql -e "create database db17" 17数据库 [root@centos37~]#mysql -e "grant all on *.* to test@'192.168.37.%' identified by 'centos' " [root@centos37~]#mysql -e "create database db37" 37数据库
3、在mysql客户端进行测试验证反向代理效果,每次访问的数据库不一定一样。
tcp负载均衡配置参数
stream { #定义stream 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 192.168.0.1:53535; #定义具体server server dns.example.com:53; } server { #定义server 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; } }