1、实现 Nginx 负载均衡的组件说明
Nginx http 功能模块 | 模块说明 |
---|---|
ngx_http_proxy_module | proxy 代理模块, 用于把请求后拋给服务器节点或 upstream 服务器池 |
ngx_http_upstream_module | 负载均衡模块, 可以实现网站的负载均衡功能及节点的健康检査 |
2、Nginx中常用模块说明
1)Nginx upstream模块
Nginx的负载均衡功能依赖于ngx_http_upsteam_module模块,所支持的代理方式包括proxy_pass、fastcgi_pass、memcached_pass等。
其中的ngx_http_upstream_module模块允许Nginx定义一组或多组节点服务器组,使用时可以通过proxy_pass代理方式把网站的请求发送到事先定义好的对应Upstream组的名字上,具体写法为“proxy_pass http:// www_server_pools”,其中www_server_pools就是一个Upstream节点服务器组名字。
ngx_http_upstream_module模块官方地址:http://nginx.org/en/docs/http/ngx_http_upstream_module.html
① upstream参数
模块内参数 | 参数说明 |
---|---|
server 10.0.10.8:80 | 负载均衡后面的RS配置,可以是 IP 或者是域名,如果端口不写,默认是 80 端口。高并发场景下, IP可换成域名,通过 DNS做负载均衡 |
weigth=1 | 代表服务器的权重,默认值是 1 。权重数字越大表示接受的请求比例越大 |
max_fails=3 | Nginx 尝试连接后端主机失败的次数,这个值是配合 proxy_next_upstream、fastcgi_next_upstream 和memcached_next_upstream 这三个参数来使用的。当 nginx 接收后端服务器返回这三个参数定义的状态码时,会将这个请求转发给正常工作的后端服务器,例如 404、502、503、Max_fails 的默认值是 1 ;企业场景下建议 2-3 次。如京东 1 次,蓝汛 10 次,根据业务需求去配置 |
fail_timeout=10s | 在 max_fails 定义的失败次数后,距离下次检查的间隔时间,默认是 10s ;如果 max_fails 是 5 ,它就检测 5 次,如果 5 次都是 502 ,那么就会根据 fail_timeout 的值,等待 10s 再去检查,还是只检查一次,如果持续 502 ,在不重新加载 Nginx 配置的情况下,每隔 10s 都只检查一次。常规业务 2~3 秒比较合理,比如京东 3 秒,蓝汛 3 秒,可根据业务需求去配置 |
backup | 热备配置( RS 节点的高可用),当前面激活的 RS 都失败后会自动启用热备 RS 这标志看这个服务器作为备份服务器,若主服务器全部宕机了,就会向它转发请求。注意:当负载调度算法为 ip_hash 时,后端服务器在负载均衡调度中的状态不能是 weight 和 backup |
down | 这标志着服务器永远不可用,这个参数可配合 ip_hash 使用,类似与注释 |
模块调度算法:
第一类:静态调度算法,即负载均衡器根据自身设定的规则进行分配,不需要考虑后端节点服务器的情况,例如:rr、wrr、ip_hash等都属于静态调度算法;
第二类:动态调度算法,即负载均衡器会根据后端节点的当前状态来决定是否分发请求,比如说连接数少的优先获得请求,响应时间短的优先获得请求。例如:least_conn、fair等都属于动态调度算法。
常用调动算法:
A.定义轮询调度算法——rr(默认调度算法)
B.定义权重调度算法——wrr
C.定义静态调度算法——ip_hash(该调度算法可以解决动态网页的session共享问题)
D.定义最小的连接数——least_conn
② 示例1:基本的upstream配置案例
upstream wwwPools {
#upstream是关键字必须有,后面的www_server_pools为一个Upstream集群组的名字,可以自己起名,调用时就用这个名字
server 192.168.0.223:80 weight=5;
server 192.168.0.224:80 weight=10;
server 192.168.0.225:80 weight=15;
#server关键字是固定的,后面可以接域名(门户会用)或IP。如果不指定端口,默认是80端口。weight代表权重,数值越大被分配的请求越多,结尾需要带分号
}
③ 示例2:较完整的upstream配置案例
upstream wwwPools {
server 192.168.0.223; #这行标签和下行是等价的
server 192.168.0.224:80 weight=1 max_fails=1 fail_timeout=10s; #这行标签和上一行是等价的,此行多余的部分就是默认配置,不写也可以。
server 192.168.0.225:80 weight=1 max_fails=2 fail_timeout=20s backup; #这行末尾的backup表示备份服务器(当其余所有服务器都宕机后才会激活使用)
#server最后面还可以添加很多参数,具体参数作用对比上方的表格
}
④ 示例3:使用域名及socket的upstream配置案例
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080; #域名加端口(转发到后端的指定端口上)
server unix:/tmp/backend3; #指定socket文件
#提示:server后面如果接域名,需要在内网配有DNS服务器或者在负载均衡器的hosts文件中添加域名解析条目
server 192.168.0.223;
server 192.168.0.224:8080;
#备份服务器,等上面指定的服务器都不可访问的时候会启动,backup的用法和Haproxy中用法一样
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
2)http_proxy_module模块
proxy_pass指令属于ngx_http_proxy_module模块,此模块可以将请求转发到另一台服务器,在实际的反向代理工作中,会通过location功能匹配指定的URI,然后把接收到的符合匹配URI的请求通过proxy_pass抛给定义好的upstream节点池。
http_proxy_module模块官方地址:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
① proxy参数
http proxy模块内参数 | 参数说明 |
---|---|
proxy_set_header | 设置 http 请求 header 项传给后端服务器节点,例如:可实现让代理后端的服务器节点获取访问客户端用户的真实 IP 地址 |
client_body_buffer_size | 用于指定客户端请求主体缓冲区大小 |
proxy_connect_timeout | 表示反向代理后端节点服务器连接的超时时间,即发起握手等候响应的超时时间 |
proxy_send_timeout | 表示代理后端服务器的数据回传时间,即在规定时间内后端服务器必须传完所有数据,否则nginx将断开这个连接 |
proxy_read_timeout | 设置 nginx 从代理的后端服务器获取信息的时间,表示连接建立成功后,nginx 等待后端服务器的响应时间,其实是 nginx 已经进入后端的排队之中等候处理的时间 |
proxy_buffer_size | 设置缓冲区大小,默认该缓冲区大小等于指令 proxy_buffers 设置的大小 |
proxy_buffers | 设置缓冲区的数量和大小,nginx 从代理的后端服务器获取的响应信息,会设置到缓冲区 |
proxy_busy_buffers_size | 用于设置相同很忙时可以使用的 proxy_buffers 大小,官方推荐的大小为 proxy_buffers * 2 |
proxy_trmp_file_write_size | 指定 proxy 缓存临时文件的大小 |
② 示例1:将匹配URI为name的请求抛给http://127.0.0.1/remote/
location /name/ {
proxy_pass http://127.0.0.1/remote/;
}
③ 示例2:将匹配URI为some/path的请求抛给http://127.0.0.1
location /some/path/ {
proxy_pass http://127.0.0.1;
}
④ 示例3:将匹配URI为name的请求应用指定的rewrite规则,随后再抛给http://127.0.0.1
location /name/ {
rewrite /name/( [^/]+ ) /username=$1 break;
proxy_pass http://127.0.0.1;
}
3、nginx负载均衡相关重要参数
Nginx反向代理重要参敎 | 解释说明 |
---|---|
proxy_pass http://server_pools; | 通过 proxy_pass 功能把用户的清求转向到反向代理定义的 upstream 服务器池 |
proxy_set_header Host $host | 在代理向后端服务器发送的 http 请求头中加入 host 字段信息,用于当后端服务器配置有多个虚拟主机时,可以识别代理的是哪个虚拟主机,是节点服务器多虚拟主机时的关键配置 |
proxy_set_header X-Forwarded-For $remote_addr; | 在代理向后端服务器发送的 http 请求头中加入 X-Forward-For 字段信息,用于后端服务器程序、日志等接收记录真实用户的 IP,而不是代理服务器的 IP这是反向代理时,节点服务器获取用户真实 IP 的必要功能配置 |
4、配置实现负载均衡
1)实验环境
代理服务器:192.168.25.138
实际内网服务器:192.168.25.136 & 192.168.25.137
客户:192.168.25.139
2)单虚拟主机节点服务器案例
① 实际内网服务器配置网站
136内网服务器
[root@136 ~]# yum install nginx -y
[root@136 ~]# vim /etc/nginx/conf.d/vhost.conf
server {
listen 80;
server_name web1.yunjisuan.com;
location / {
root /usr/share/nginx/html/web1;
index index.html index.htm;
}
access_log /usr/share/nginx/html/web1/logs/access_bbs.log main;
}
[root@136 ~]# mkdir -p /usr/share/nginx/html/web1/logs
[root@136 ~]# echo "`hostname -I `web1" > /usr/share/nginx/html/web1/index.html
[root@136 ~]# nginx -t #测试语法问题
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@136 ~]# systemctl restart nginx #重启
137内网服务器
[root@137 ~]# yum install nginx -y
[root@137 ~]# vim /etc/nginx/conf.d/vhost.conf
server {
listen 80;
server_name web1.yunjisuan.com;
location / {
root /usr/share/nginx/html/web1;
index index.html index.htm;
}
access_log /usr/share/nginx/html/web1/logs/access_bbs.log main;
}
[root@137 ~]# mkdir -p /usr/share/nginx/html/web1/logs
[root@137 ~]# echo "`hostname -I `web1" > /usr/share/nginx/html/web1/index.html
[root@137 ~]# nginx -t #测试语法问题
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@137 ~]# systemctl restart nginx #重启
② 代理服务器配置负载均衡
138代理服务器
[root@138 ~]# yum install nginx -y
[root@138 ~]# vim /etc/nginx/conf.d/lb_test.conf
upstream www_server_pools {
#定义“www_server_pools”服务器池,包含了136、137两个Web节点,权值均为1
server 192.168.25.136:80 weight=1;
server 192.168.25.137:80 weight=1;
}
server {
listen 80;
server_name web1.yunjisuan.com;
location / {
proxy_pass http://www_server_pools; #调用“www_server_pools”服务器池
}
}
[root@138 ~]# nginx -t #测试语法问题
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@138 ~]# systemctl restart nginx #重启
③ 客户测试
139客户
配置hosts文件
[root@139 ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.25.138 web1.yunjisuan.com
使用for循环进行循环访问测试四次
[root@139 ~]# for ((i=1;i<=4;i++)); do curl http://web1.yunjisuan.com; done
192.168.25.137 web1
192.168.25.136 web1
192.168.25.137 web1
192.168.25.136 web1
#可以清晰看出权值为1时,每个服务器轮流被访问
3)多虚拟主机节点服务器案例
① 实际内网服务器配置网站
136内网服务器
[root@136 ~]# yum install nginx -y
[root@136 ~]# vim /etc/nginx/conf.d/vhost.conf
server {
listen 80;
server_name web1.yunjisuan.com;
location / {
root /usr/share/nginx/html/web1;
index index.html index.htm;
}
access_log /usr/share/nginx/html/web1/logs/access_bbs.log main;
}
server {
listen 80;
server_name web2.yunjisuan.com;
location / {
root /usr/share/nginx/html/web2;
index index.html index.htm;
}
access_log /usr/share/nginx/html/web2/logs/access_www.log main;
}
[root@136 ~]# mkdir -p /usr/share/nginx/html/{web1,web2}/logs
[root@136 ~]# echo "`hostname -I `web1" > /usr/share/nginx/html/web1/index.html
[root@136 ~]# echo "`hostname -I `web2" > /usr/share/nginx/html/web2/index.html
[root@136 ~]# nginx -t #测试语法问题
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@136 ~]# systemctl restart nginx #重启
137内网服务器
[root@137 ~]# yum install nginx -y
[root@137 ~]# vim /etc/nginx/conf.d/vhost.conf
server {
listen 80;
server_name web1.yunjisuan.com;
location / {
root /usr/share/nginx/html/web1;
index index.html index.htm;
}
access_log /usr/share/nginx/html/web1/logs/access_bbs.log main;
}
server {
listen 80;
server_name web2.yunjisuan.com;
location / {
root /usr/share/nginx/html/web2;
index index.html index.htm;
}
access_log /usr/share/nginx/html/web2/logs/access_www.log main;
}
[root@137 ~]# mkdir -p /usr/share/nginx/html/{web1,web2}/logs
[root@137 ~]# echo "`hostname -I `web1" > /usr/share/nginx/html/web1/index.html
[root@137 ~]# echo "`hostname -I `web2" > /usr/share/nginx/html/web2/index.html
[root@137 ~]# nginx -t #测试语法问题
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@137 ~]# systemctl restart nginx #重启
② 代理服务器配置负载均衡
138代理服务器
[root@138 ~]# yum install nginx -y
[root@138 ~]# vim /etc/nginx/conf.d/lb_test.conf
upstream www_server_pools {
#定义“www_server_pools”服务器池,包含了136、137两个Web节点,权值均为1
server 192.168.25.136:80 weight=1;
server 192.168.25.137:80 weight=1;
}
server {
listen 80;
server_name web1.yunjisuan.com;
location / {
proxy_pass http://www_server_pools; #调用“www_server_pools”服务器池
proxy_set_header Host $host; #告知代理服务器如何识别多个不同虚拟主机
}
}
server {
listen 80;
server_name web2.yunjisuan.com;
location / {
proxy_pass http://www_server_pools; #调用“www_server_pools”服务器池
proxy_set_header Host $host; #告知代理服务器如何识别多个不同虚拟主机
}
}
[root@138 ~]# nginx -t #测试语法问题
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@138 ~]# systemctl restart nginx #重启
③ 客户测试
139客户
配置hosts文件
[root@139 ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.25.138 web1.yunjisuan.com web2.yunjisuan.com
使用for循环进行循环访问测试四次
[root@139 ~]# for ((i=1;i<=4;i++)); do curl http://web1.yunjisuan.com; done
192.168.25.137 web1
192.168.25.136 web1
192.168.25.137 web1
192.168.25.136 web1
[root@139 ~]# for ((i=1;i<=4;i++)); do curl http://web2.yunjisuan.com; done
192.168.25.136 web2
192.168.25.137 web2
192.168.25.136 web2
192.168.25.137 web2
#可以清晰看出权值为1时,两个虚拟主机的每个服务器都是轮流被访问
5、故障报错
nginx反向代理报错400
故障报错原因:根据400报错以及对http协议的原理了解得知是因为请求头的原因,原因是因为upstream后面的名称有下划线使得代理无法识别。