Nginx反向代理及负载均衡
实验环境
四台虚拟机
IP 说明 172.25.254.101 nginx负载均衡器 172.25.254.102 客户端 172.25.254.103 web服务器1 172.25.254.104 web服务器2
一、nginx反向代理
1.1 nginx反向代理原理
反向代理服务器架设在服务器端,通过缓冲经常被请求的页面来缓解服务器的工作量,将客户机请求转发给内部网络上的目标服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器与目标主机一起对外表现为一个服务器。
Nginx 反向代理的原理是将客户端的请求转发到后端真实服务器,并将后端服务器的响应返回给客户端,同时对客户端隐藏后端服务器的真实信息。以下是其详细原理:
- 客户端发起请求:客户端向 Nginx 反向代理服务器发送请求,请求中包含目标 URL 等信息。
- Nginx 接收请求:Nginx 监听在特定的端口上,接收客户端的请求。它会根据配置文件中的规则来判断如何处理该请求。
- 请求匹配与转发:Nginx 根据配置的虚拟主机、域名、URL 路径等规则,将请求匹配到对应的后端服务器组。然后,Nginx 会选择一台后端服务器,并将请求转发给它。
- 后端服务器处理请求:后端服务器接收到 Nginx 转发的请求后,进行相应的处理,如查询数据库、执行应用程序逻辑等,生成响应数据。
- Nginx 接收后端服务器响应:后端服务器将响应数据发送给 Nginx。
- Nginx 将响应返回给客户端:Nginx 接收后端服务器的响应后,根据配置进行一些额外的处理,如添加响应头、缓存响应等,然后将响应数据返回给客户端。
通过以上过程,Nginx 作为反向代理服务器,充当了客户端和后端服务器之间的中间桥梁,实现了对后端服务器的负载均衡、缓存加速、安全防护等功能,同时提高了系统的性能和可扩展性。
1.2 nginx反向代理配置
安装nginx
## 在nginx负载均衡器和服务器三台机器上分别安装nginx [root@Rocky ~]# dnf install nginx -y
配置用于测试的Web服务(以下操作在两台web服务器)
## 创建日志文件目录 [root@Rocky ~]# mkdir -p /usr/share/nginx/html/{www,bbs}/logs [root@Rocky ~]# cd /etc/nginx/conf.d/ [root@Rocky conf.d]# vim vhost.conf [root@Rocky conf.d]# cat vhost.conf server { listen 80; server_name bbs.yunjisuan.com; location / { root /usr/share/nginx/html/bbs; index index.html index.htm; } access_log /usr/share/nginx/html/bbs/logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root /usr/share/nginx/html/www; index index.html index.htm; } access_log /usr/share/nginx/html/www/logs/access_www.log main; } ## 检查是否有语法错误 [root@Rocky conf.d]# nginx -t [root@Rocky conf.d]# echo "`hostname -I ` . www" > /usr/share/nginx/html/www/index.html [root@Rocky conf.d]# echo "`hostname -I ` . bbs" > /usr/share/nginx/html/bbs/index.html ## 启动服务测试 [root@Rocky conf.d]# systemctl start nginx [root@Rocky ~]# curl -H host:bbs.yunjisuan.com 172.25.254.103 172.25.254.103 . bbs [root@Rocky ~]# curl -H host:bbs.yunjisuan.com 172.25.254.104 172.25.254.104 . bbs [root@Rocky ~]# curl -H host:www.yunjisuan.com 172.25.254.104 172.25.254.104 . www [root@Rocky ~]# curl -H host:www.yunjisuan.com 172.25.254.103 172.25.254.103 . www
二、nginx负载均衡
Nginx 通过反向代理实现负载均衡,客户端的请求先到达 Nginx,Nginx 依据配置规则,把请求转发给不同的后端服务器,并将处理结果返回给客户端。其采用多进程 + 异步非阻塞 I/O 事件模型,能高效处理大量并发请求。
2.1 nginx模块
Nginx的负载均衡功能依赖于ngx_http_upsteam_module
模块,所支持的代理方式包括proxy_pass
,fastcgi_pass
,memcached_pass
等,新版Nginx软件支持的方式有所增加。本文主要讲解proxy_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。
示例1:基本的upstream配置案例
upstream www_server_pools { #upstream是关键字必须有,后面的www_server_pools为一个Upstream集群组的名字,可以自己起名,调用时就用这个名字 server 172.25.254.223:80 weight=5; server 172.25.254.224:80 weight=10; server 172.25.254.225:80 weight=15; #server关键字是固定的,后面可以接域名(门户会用)或IP。如果不指定端口,默认是80端口。weight代表权重,数值越大被分配的请求越多,结尾有分号。 }
示例2:较完整的upstream配置案例
upstream www_server_pools { server 172.25.254.223; #这行标签和下行是等价的 server 172.25.254.224:80 weight=1 max_fails=1 fail_timeout=10s; #这行标签和上一行是等价的,此行多余的部分就是默认配置,不写也可以。 server 172.25.254.225:80 weight=1 max_fails=2 fail_timeout=20s 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 172.25.254.223; server 172.25.254.224:8080; server backup1.example.com:8080 backup; #备份服务器,等上面指定的服务器都不可访问的时候会启动,backup的用法和Haproxy中用法一样 server backup2.example.com:8080 backup; }
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使用;类似与注释。
2.1 常用模块调度算法
- 轮询(roundrobin):按顺序依次将请求分发到后端服务器,从第一台开始,到最后一台后再回到第一台,循环进行,不考虑服务器性能差异和负载情况,均等分配请求。
- 加权轮询(weight):在轮询基础上,为各后端服务器设置权重,权重代表服务器处理请求的能力。权重越高,被分配到请求的概率越大,按权重比例分配请求,用于后端服务器性能不均衡场景。
- IP 哈希(ip_hash):对客户端 IP 地址进行哈希运算,通过哈希值与后端服务器列表映射,使同一客户端的请求始终发往同一台后端服务器,以维持客户端会话状态。
- 最少连接数(least_conn):将请求分配给当前连接数最少的后端服务器,实时监测服务器连接数,优先选择连接数少的服务器处理新请求,让负载更均衡,适合处理请求时间差异大的场景。
- 基于响应时间的调度(fair):借助第三方模块实现,依据后端服务器的响应时间分配请求。响应时间短的服务器,接收新请求的概率高,能让客户端更快得到响应,适用于对响应时间要求高的应用。
2.3http_proxy_module
模块
特性 | 详情 |
---|---|
功能 | 用于将客户端请求转发到后端HTTP服务器,实现反向代理和负载均衡 |
指令 | |
proxy_pass |
指定后端服务器地址,可以是IP地址加端口,也可以是一个定义好的upstream 组名。例如proxy_pass http://backend_server; ,其中backend_server 可以是具体地址如192.168.1.100:8080 ,也可以是在upstream 块中定义的服务器组。 |
proxy_set_header |
设置转发到后端服务器的请求头。如proxy_set_header Host $host; ,将客户端请求中的Host 头原封不动转发给后端服务器,还可自定义头信息,像proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 用于记录客户端真实IP。 |
proxy_connect_timeout |
设置与后端服务器建立连接的超时时间。默认60秒,例如proxy_connect_timeout 30s; ,表示尝试连接后端服务器超过30秒未成功则连接失败。 |
proxy_read_timeout |
设置从后端服务器读取响应的超时时间。默认60秒,即如果在这个时间内没有从后端服务器读取到任何数据,连接将被关闭,如proxy_read_timeout 90s; |
proxy_send_timeout |
设置向后端服务器发送请求的超时时间。默认60秒,若在该时间内没有成功将请求数据发送到后端服务器,连接将被关闭,如proxy_send_timeout 45s; |
proxy_buffer_size |
设置用于读取后端服务器响应头的缓冲区大小。默认与proxy_buffers 中的一个缓冲区大小相同,可根据实际情况调整,如proxy_buffer_size 128k; |
proxy_buffers |
设置用于读取后端服务器响应正文的缓冲区数量和大小。例如proxy_buffers 4 256k; 表示设置4个大小为256KB的缓冲区。 |
proxy_busy_buffers_size |
设置处于繁忙状态(正在被读取或写入)的缓冲区最大大小。默认值是proxy_buffers 中两个缓冲区的大小,如proxy_busy_buffers_size 512k; |
proxy_temp_path |
设置临时文件存储路径,用于存储在处理大文件上传或响应时产生的临时数据。例如proxy_temp_path /var/tmp/nginx_proxy; 。 |
工作机制 | 客户端向Nginx发起请求,Nginx根据配置的proxy_pass 指令将请求转发到后端服务器。在转发过程中,可通过proxy_set_header 等指令修改请求头信息。Nginx等待后端服务器响应,根据设置的各种超时指令控制连接和数据传输的时间。响应数据返回后,Nginx根据缓冲区相关指令处理响应数据,再返回给客户端。 |
应用场景 | 广泛应用于Web服务器集群,实现反向代理和负载均衡,隐藏后端服务器真实IP,提升安全性;还可用于缓存加速,将频繁访问的内容缓存到Nginx,减少后端服务器压力。 |
示例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; }
2.4 nginx负载均衡配置:
web服务器配置如上
配置nginx负载均衡器
[root@Rocky ~]# /etc/nginx/conf.d [root@Rocky conf.d]# vim vhost.conf upstream www_server_pools { server 172.25.254.103; #默认监听端口80 server 172.25.254.104; } server { listen 80; server_name www.yunjisuan.com; location / { proxy_pass http://www_server_pools; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } } server { listen 80; server_name bbs.yunjisuan.com; location / { proxy_pass http://www_server_pools; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } } [root@Rocky conf.d]# nginx -t [root@Rocky conf.d]# nginx -s reload
在客户端测试
## 配置host解析 [root@Rocky ~]# vim /etc/hosts 172.25.254.101 bbs.yunjisuan.com www.yunjisuan.com [root@Rocky ~]# for ((i=1;i<=4;i++)); do curl http://bbs.yunjisuan.com; done 172.25.254.103 . bbs 172.25.254.104 . bbs 172.25.254.103 . bbs 172.25.254.104 . bbs [root@Rocky ~]# for ((i=1;i<=4;i++)); do curl http://www.yunjisuan.com; done 172.25.254.103 . www 172.25.254.104 . www 172.25.254.103 . www 172.25.254.104 . www ## 从上面的测试结果可以看出来。两个Web节点按照1:1的比例被访问。 ## 下面宕掉任意一个Web节点,看看测试结果如何,测试如下 ## 在172.25.254.103主机上停止nginx服务 [root@Rocky conf.d]# systemctl stop nginx ## 继续测试 [root@Rocky ~]# for ((i=1;i<=4;i++)); do curl http://www.yunjisuan.com; done 172.25.254.104 . www 172.25.254.104 . www 172.25.254.104 . www 172.25.254.104 . www [root@Rocky ~]# for ((i=1;i<=4;i++)); do curl http://bbs.yunjisuan.com; done 172.25.254.104 . bbs 172.25.254.104 . bbs 172.25.254.104 . bbs 172.25.254.104 . bbs
由于添加
proxy_set_header X-Forwarded-For $remote_addr
,我们可以在web服务器的日志上查看真实访问ip[root@Rocky ~]# tail -3 /usr/share/nginx/html/www/logs/access_www.log 172.25.254.101 - - [17/Mar/2025:17:34:08 +0800] "GET / HTTP/1.0" 200 21 "-" "curl/7.61.1" "172.25.254.102" 172.25.254.101 - - [17/Mar/2025:17:34:08 +0800] "GET / HTTP/1.0" 200 21 "-" "curl/7.61.1" "172.25.254.102" 172.25.254.101 - - [17/Mar/2025:17:34:08 +0800] "GET / HTTP/1.0" 200 21 "-" "curl/7.61.1" "172.25.254.102" [root@Rocky ~]# tail -3 /usr/share/nginx/html/bbs/logs/access_bbs.log 172.25.254.101 - - [17/Mar/2025:17:34:15 +0800] "GET / HTTP/1.0" 200 21 "-" "curl/7.61.1" "172.25.254.102" 172.25.254.101 - - [17/Mar/2025:17:34:15 +0800] "GET / HTTP/1.0" 200 21 "-" "curl/7.61.1" "172.25.254.102" 172.25.254.101 - - [17/Mar/2025:17:34:15 +0800] "GET / HTTP/1.0" 200 21 "-" "curl/7.61.1" "172.25.254.102"