Nginx 负载均衡
集群
Nginx 标准 HTTP 模块 ngx_http_upstream_module 内置了集群和负载均衡功能,使用其中的 upstream
配合 proxy_pass
指令即可快速实现一个集群:
1 | http { |
其中 server
指令的常用参数描述如下:
参数 | 描述 |
---|---|
weight=number |
设置服务器的轮询权重,默认为 1。用于后端服务器性能不均的情况。 |
max_conns=number |
设置被代理服务器的最大可用并发连接数限制,默认为 0,表示没有限制。 |
max_fails=number |
设置最大失败重试次数,默认为 1。设置为 0 表示禁用重试。 |
fail_timeout=time |
设置失败时间,默认 10 秒。 |
backup |
将服务器标记为备份服务器。当主服务器不可用时,它将被传递请求。 |
down |
将服务器标记为永久不可用。 |
负载均衡
负载均衡(Load Balance),其意思就是将运算或存储负载按一定的算法分摊到多个运算或存储单元上,下面介绍 Nginx 几种常见的负载均衡方法:
- 默认策略:加权轮询策略(weighted round-robin)。
random
,加权随机策略。ip_hash
,基于客户端 IP 计算出哈希值,再根据服务器数量取模选取服务器(ip_hash % server_size = server_no)。hash key [consistent]
,基于指定 key 计算出哈希值,再根据服务器数量取模选取服务器。可选一致性哈希算法缓解重映射问题。least_conn
,基于最小活跃连接数(加权)。如果有多个服务器符合条件,则使用加权轮询策略依次响应。least_time
,基于最小平均响应时间和最小活跃连接数(加权)。如果有多个服务器符合条件,则使用加权轮询策略依次响应。
ip hash
使用 Nginx ip_hash
指令,配置如下:
1 | upstream backend { |
ip_hash
指令指定集群使用基于客户端 IP 地址的负载均衡方法。 客户端 IPv4 地址的前三个八位字节或整个 IPv6 地址用作哈希键。 该方法确保来自同一客户端的请求将始终传递到同一台服务器,除非此服务器不可用,客户端请求则将被转发到另一台服务器(多数情况下,始终是同一台服务器)。
如果其中一台服务器需要临时删除,则应使用 down
参数标记,以便保留当前客户端 IP 地址的哈希值。
一致性 hash
使用 Nginx hash
指令,常用的例如基于来源 IP 进行哈希,配置如下:
1 | upstream backend { |
hash
指令指定集群使用基于指定 hash 散列键的负载均衡方法。散列键可以包含文本,变量及其组合。请注意,从集群中添加或删除服务器可能会导致大量键被重新映射到不同的服务器。
解决办法是使用 consistent
参数启用 ketama 一致性 hash 算法。 该算法将每个 server 虚拟成 n 个节点,均匀分布到 hash 环上。每次请求,根据配置的参数计算出一个 hash 值,在 hash 环上查找离这个 hash 最近的虚拟节点,对应的 server 作为该次请求的后端服务器。该算法确保在添加或删除服务器时,只会有少量键被重新映射到不同的服务器。这有助于为缓存服务器实现更高的缓存命中率。
会话保持
为了确保与某个客户端相关的所有请求都能够由同一台服务器进行处理,我们需要在负载均衡上启用会话保持功能,以确保负载均衡的部署不会影响到正常的业务处理,避免会话丢失。
Nginx 会话保持一般有两种方案:
- 基于源 IP 地址的 ip_hash
- sticky cookie 粘滞会话(也称会话保持\会话绑定)
ip_hash 实现会话保持的问题在于,当多个客户是通过正向代理(如翻墙)或 NAT 地址转换的方式来访问服务器时,由于都分配到同一台服务器上,会导致服务器之间的负载失衡。
sticky cookie 实现会话保持,在一定条件下可以保证同一个客户端访问的都是同一个后端服务器。通过 Nginx sticky
指令,配置如下:
1 | upstream backend { |
下面这份配置在同一域名下有两个 location,分别对应了两组集群服务。为了分别实现会话保持,将 cookie 写入了对应的 path 下,避免 cookie 互相干扰,也减少了数据传输量:
1 | http { |
健康检查
健康检查(Health Check)是保障集群可用性的重要手段,有三种常见的健康检查方法:
- 使用社区版 Nginx 的
max_fails
和fail_timeout
指令进行被动式检查,不推荐使用,详见:《nginx中健康检查(health_check)机制深入分析》; - 使用商业版 Nginx Plus 进行主动式检查,缺点是要收费;
- 使用 Nginx 第三方模块编译,例如:nginx_upstream_check_module ;
- 使用 Tengine 内置的主动式健康检查功能(该内置模块等同于第 3 点)。
主动式健康检查
以 nginx_upstream_check_module
第三方模块为例,演示配置如下:
1 | upstream backend1 { |
这段配置表示:
check
指令配置:每隔interval
毫秒主动发送一个http
健康检查包给后端服务器。请求超时时间为timeout
毫秒。如果连续失败次数达到fall_count
,服务器就被认为是 down;如果连续成功次数达到rise_count
,服务器就被认为是 up。check_keepalive_requests
指令配置:一个连接发送的请求数。check_http_send
指令配置:请求包的内容(注意,这里必须配置Host
请求头否则可能报错)。check_http_expect_alive
指令配置:响应状态码为2XX
和3XX
表示请求成功、服务健康。
查看 Tomcat access.log 如下:
1 | 127.0.0.1 - - [06/Jun/2017:21:03:30 +0800] "HEAD /m/monitor.html HTTP/1.1" 200 - |
此时关闭某台后端服务器,一段时间后再访问,请求会被路由到其它服务器;重启后,该服务器自动加入集群。通过健康状态页面 /status
可见:
1 | Nginx http upstream check status |
常用变量
$upstream_addr
该模块中很常用的一个变量,用于标识集群中服务器的 IP 和端口。一般会加入到 Nginx 日志、同时脱敏后加入到响应头中,用于排查问题来源:
1 | http { |