Nginx反向代理的负载均衡配置
Nginx 负载均衡详解
在互联网应用中,随着网站访问量的不断攀升,服务器的服务模式也需要进行相应升级。诸如分离数据库服务器、将图片作为单独服务等操作,这些都属于简单的数据负载均衡,其目的是将压力分散到不同机器上。而来自 Web 前端的压力同样不容忽视,如何将同一个域名的访问请求分散到两台或更多机器上呢?Nginx 自身就能实现这一功能,只需进行简单的配置即可。
Nginx 不仅是强大的 Web 服务器,还可以作为反向代理服务器。此外,它能够依据调度规则实现动态、静态页面的分离,并且支持按照轮询、IP 哈希、URL 哈希、权重等多种方式对后端服务器进行负载均衡,同时还具备后端服务器健康检查的功能。
Nginx 负载均衡基础知识
Nginx 的upstream目前支持下面几种请求分配方式:
轮询(默认):每个请求按照时间顺序依次分配到不同的后端服务器,当后端服务器出现故障(down 掉)时,Nginx 能够自动将其剔除。
weight:通过指定轮询几率,weight值与访问比率成正比,适用于后端服务器性能不均衡的场景。
ip_hash:每个请求依据访问 IP 的哈希结果进行分配,如此一来,每个访客将固定访问某一个后端服务器,能够有效解决 session 问题。
fair(第三方):按照后端服务器的响应时间分配请求,响应时间短的服务器优先接收请求。
url_hash(第三方)
Nginx 负载均衡配置
在 Nginx 的http段进行如下配置,即可实现针对不同域名的负载均衡:
http {upstream www.linuxidc.com {server 1.0.1.50:8080;server 1.0.1.51:8080;}upstream blog.linuxidc.com {server 1.0.1.50:8080;server 1.0.1.51:8080;}server {listen 80;server_name www.xxx.com;location / {proxy_pass http://www.linuxidc.com;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}server {listen 80;server_name blog.xxx.com wode.xxx.com;location / {proxy_pass http://www.xxx.com;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}
}
注意事项
3.1 多台机器间 session 共享问题
配置负载均衡相对容易,但其中最关键的问题是如何实现多台服务器之间的 session 共享,以下是几种常见的解决方法(部分内容来源于网络,第四种方法未经实践验证):
- 不使用 session,换用 cookie:将 session 替换为 cookie 可以避开 session 的一些弊端。在早期的
J2EE 书籍中也提到,在集群系统中不宜使用 session,否则可能引发问题。如果系统不太复杂,可优先考虑去掉
session;若改动难度较大,则可尝试其他方法。 - 应用服务器自行实现共享:以 PHP 为例,可以使用数据库或 memcached 来保存 session,从而在 PHP 层面构建一个
session 集群。这种方式能够确保 session 的稳定性,即便某个节点出现故障,session 也不会丢失,适用于对
session 稳定性要求较高但请求量不大的场景。不过,其效率相对较低,不太适合对效率要求严苛的场合。 - ip_hash:Nginx 中的ip_hash技术能够将来自某个 IP 的请求定向到同一台后端服务器,这样该 IP
下的客户端与后端服务器就能建立稳定的 session。在upstream配置中定义ip_hash的方式如下:
upstream backend {server 127.0.0.1:8080;server 127.0.0.1:9090;ip_hash;
}
ip_hash原理简单易懂,但由于仅依据 IP 地址来分配后端服务器,存在一定局限性,在以下情况下不适用:
- Nginx 不是最前端的服务器:ip_hash要求 Nginx 必须是最前端的服务器,否则 Nginx 无法获取正确的客户端
IP,也就无法基于 IP 进行哈希计算。例如,当使用 Squid 作为最前端服务器时,Nginx 获取到的 IP 地址仅是 Squid
服务器的 IP,以此进行分流会导致请求错乱。 - Nginx 的后端还有其它方式的负载均衡:如果 Nginx
后端还存在其他负载均衡方式,将请求再次分流,那么某个客户端的请求将无法始终定位到同一台 session 应用服务器上。因此,Nginx
后端最好直接指向应用服务器,或者再搭建一个 Squid 后指向应用服务器。也可以使用location进行分流,将需要 session
的请求通过ip_hash处理,其余请求通过其他后端处理。 - upstream_hash:为解决ip_hash的部分问题,可以使用upstream_hash这个第三方模块。该模块通常用于url_hash,但也可用于实现
session 共享。当前端是 Squid 时,Squid 会将客户端 IP 添加到x_forwarded_for这个 HTTP
头中,通过upstream_hash可以利用该头部信息作为因子,将请求定向到指定后端。
。在文档中默认使用$request_uri作为因子,可根据需求修改,例如:
hash $http_x_forwarded_for;
上述配置将使用x_forwarded_for头部信息作为哈希因子。在 Nginx 新版本中,还支持读取 cookie 值,可修改为:
nginx
hash $cookie_jsessionid;
如果在 PHP 中配置 session 为无 cookie 方式,可配合 Nginx 的userid_module模块由 Nginx 自动生成一个 cookie,另外,还可使用姚伟斌编写的upstream_jvm_route模块
3.2 后端服务器自动加上端口的问题
在典型的 Nginx + Apache 应用方案中,通常 Nginx 占用 80 端口,负责过滤静态请求,将动态请求代理(Proxy)到 Apache 的 8080 端口。反向代理的优势在于用户访问时始终使用 80 端口,不会察觉到后端服务器的差异。然而,有些应用会识别到 Apache 所在的端口是 8080,并在相关超链接中自动加上:8080,这将导致访问异常。解决该问题的一种方法是让 Apache 也运行在 80 端口上。在同一台服务器上同时运行 Nginx 和 Apache 两个 HTTPD 服务且都使用 80 端口,可通过以下配置避免冲突:
修改 Nginx 的配置文件nginx.conf,将:
server {listen 80;server_name www.linuxidc.com;...
}
修改为:
server {listen 123.123.123.123:80; #指定Nginx只占用某个公网IP的80端口。#listen 123.123.123.124:80; #如果服务器中有多个IP,还可以指定多个。server_name www.linuxidc.com;...
}
修改 Apache 的配置文件httpd.conf,将:
Listen 80
改为:
apache
Listen 127.0.0.1:80
完成上述配置修改后,保存文件并重启 Apache 服务即可生效。