介绍
在多个应用实例间做负载均衡是一个被广泛使用的技术,用于优化资源效率,最大化吞吐量,减少延迟和容错。
负载均衡的几个重要的点:
- 上游服务器配置 :使用upstream server配置多个上游服务器。
- 负载均衡算法 :配置多个上游服务器时的负载均衡机制。
- 失败重试机制 :配置当超时或上游服务器不存活时,是否需要重试其他上游服务器。
- 服务器心跳检查 :上游服务器的健康检查/心跳检查。
负载均衡方法
请求转发的策略。
- round-robin/轮询(默认): 到应用服务器的请求以round-robin/轮询的方式被分发
- least-connected/最少连接:下一个请求将被分派到活动连接数量最少的服务器
- ip-hash/IP散列: 使用hash算法来决定下一个请求要选择哪个服务器(基于客户端IP地址)
Nginx 配置
1. 基本配置
http {
upstream myapp1 {
// 负载均衡的方法,默认为 round-robin
// least_conn;
// ip_hash;
// 均衡的服务器清单
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://myapp1;
}
}
}
2. 权重配置
可以更具服务器的性能,进行权重的配置
upstream myapp1 {
server srv1.example.com weight=3;
server srv2.example.com;
server srv3.example.com;
}
在这个配置中,每5个新请求将会如下的在应用实例中分派: 3个请求分派去srv1,一个去srv2,另外一个去srv3.
在最近的nginx版本中,可以类似的在最少连接和IP哈希负载均衡中使用权重。
健康检测
Upstream 服务器节点的健康检测 及 分发控制。
被动能做到访问那一刻失败的,可以重新分发到其他的节点;主动可以提前做好监测,避免错误碰撞。
1. 被动的健康检测
通过 nginx 自带的 ngx_http_proxy_module 模块 和 ngx_http_upstream_module模块进行检测,对具体的请求结果分析,判断该服务器节点是否有问题。
http {
upstream myapp1 {
// ngx_http_upstream_module。失败1次后,即停止向该服务器分发,直到 10秒后重新分发
server srv1.example.com weight=1 max_fails=1 fail_timeout=10;
server srv2.example.com weight=1 max_fails=1 fail_timeout=10;
server srv3.example.com weight=1 max_fails=1 fail_timeout=10;
}
server {
listen 80;
// ngx_http_proxy_module
proxy_send_timeout=60;
proxy_connect_timeout=60;
proxy_read_timeout=60;
proxy_next_upstream=error timeout; // 默认
location / {
proxy_pass http://myapp1;
}
}
}
- fail_timeout — 该参数表示停止分发请求至该应用服务器的时间
- max_fails — 设置访问失败的最大次数
- proxy_connect_timeout - 设置与后端服务器建立连接的超时时间
- proxy_read_timeout - 定义从后端服务器读取响应的超时。此超时是指相邻两次读操作之间的最长时间间隔,而不是整个响应传输完成的最长时间。如果后端服务器在超时时间段内没有传输任何数据,连接将被关闭
- proxy_next_upstream - 指定在何种情况下一个失败的请求应该被发送到下一台后端服务器
error # 和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现错误
timeout # 和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现超时
invalid_header # 后端服务器返回空响应或者非法响应头
http_500 # 后端服务器返回的响应状态码为500
http_502 # 后端服务器返回的响应状态码为502
http_503 # 后端服务器返回的响应状态码为503
http_504 # 后端服务器返回的响应状态码为504
http_404 # 后端服务器返回的响应状态码为404
off # 停止将请求发送给下一台后端服务器
出现 error 的场景,常见的是上游服务器的服务重启、停止,或者异常崩溃导致的无法提供正常服务。而 timeout 的情况,就是代理请求过程中达到对应的超时配置,主要包括了:
proxy_connect_timeout,建立三次握手的时间
proxy_read_timeout,建立连接后,等待上游服务器响应以及处理请求的时间
proxy_send_timeout,数据回传的间隔时间(注意不是数据发送耗时)
2. 主动的健康检测
主动定时向每台服务器发送指令,来监测是否正常。主要以下两种:
- nginx_upstream_check_module模块
- ngx_http_healthcheck_module模块
2.1 nginx_upstream_check_module模块
除了自带的上述模块,还有一个更专业的模块,来专门提供负载均衡器内节点的健康检查的。这个就是淘宝技术团队开发的 nginx 模块。
在淘宝自己的 tengine 上是自带了该模块的,大家可以访问淘宝tengine的官网来获取该版本的nginx,官方地址:http://tengine.taobao.org/ 。
upstream name {
server 192.168.0.21:80;
server 192.168.0.22:80;
// 对所有节点,每个3秒检测一次,请求2次正常则标记 realserver状态为up,如果检测 5 次都失败,则标记 realserver的状态为down,超时时间为1秒
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
// check_http_send "HEAD /status HTTP/1.0\r\n\r\n";
// check_http_expect_alive http_2xx http_3xx;
}
参数
- interval:向后端发送的健康检查包的间隔。
- fall(fall_count): 如果连续失败次数达到fall_count,服务器就被认为是down。
- rise(rise_count): 如果连续成功次数达到rise_count,服务器就被认为是up。
- timeout: 后端健康请求的超时时间。
- default_down: 设定初始时服务器的状态,如果是true,就说明默认是down的,如果是false,就是up的。默认值是true,也就是一开始服务器认为是不可用,要等健康检查包达到一定成功次数以后才会被认为是健康的。
- type:健康检查包的类型,现在支持以下多种类型
- tcp:简单的tcp连接,如果连接成功,就说明后端正常。
- ssl_hello:发送一个初始的SSL hello包并接受服务器的SSL hello包。
- http:发送HTTP请求,通过后端的回复包的状态来判断后端是否存活。
- mysql: 向mysql服务器连接,通过接收服务器的greeting包来判断后端是否存活。
- ajp:向后端发送AJP协议的Cping包,通过接收Cpong包来判断后端是否存活。
- port: 指定后端服务器的检查端口。你可以指定不同于真实服务的后端服务器的端口,比如后端提供的是443端口的应用,你可以去检查80端口的状态来判断后端健康状况。默认是0,表示跟后端server提供真实服务的端口一样。该选项出现于Tengine-1.4.0
健康服务器查看页面
在Tengine-1.4.0以后,你可以配置显示页面的格式。支持的格式有: html、csv、 json。默认类型是html。
你也可以通过请求的参数来指定格式,假设‘/status’是你状态页面的URL, format参数改变页面的格式,比如:
/server_status?format=html
/server_status?format=csv
/server_status?format=json
同时你也可以通过status参数来获取相同服务器状态的列表,比如:
/server_status?format=html&status=down
/server_status?format=csv&status=up
下面是一个状态也配置的范例:
http {
server {
// 定义服务器的查看地址(可以通过程序灵活控制当前机器的工作状态)
location /server_status {
check_status;
access_log off;
}
}
}
2.2 health_check
只有商业版的 nginx 可用,这里不作详细介绍。主要是通过 health_check + zone 指令
http {
upstream onmpw {
// zone指令定义了一块儿内存空间。这块儿空间存储在各个工作进程中共享的运行环境的状态和应用服务器组的配置信息
zone onmpw 64k;
server 192.168.144.128;
server 192.168.144.132;
server 192.168.144.131;
}
server {
listen 80;
location / {
proxy_pass http://onmpw;
// interval=10: 每隔10秒向服务器发送一个 / http 请求,如果没有返回 2xx 或者 3xx,都认为失败
// fails=3: 如果请求失败次数达到3次,则该应用服务器被认为不能访问
// passes=2: 被认定为不能访问的服务器需要再次进行两次health_check 以后才会再次被认为是可以正常访问的
// uri=/some/path: 指定 health check 的地址
health_check interval=10 fails=3 passes=2;
}
}
}
Upstream 的动态负载均衡
我们可以发现,如果每次upstream列表有改动,都需要到服务器进行修改。
更好的做法是实现upstream服务的自动发现。
Consul是一款开源的分布式服务注册与发现系统,通过HTTP API可以使得服务注册、发现实现起来非常简单,它支持如下特性。
- 服务注册: 服务实现者可以通过HTTP API或DNS方式,将服务注册到Consul。
- 服务发现: 服务消费者可以通过HTTP API或DNS方式,从Consul获取服务的IP 和PORT。
- 故障检测: 支持如TCP、HTTP等方式的健康检查机制,从而当服务有故障时自动摘除。
- K/V存储: 使用K/V存储实现动态配置中心,其使用HTTP长轮询实现变更触发和配置更改。
- 多数据中心: 支持多数据中心,可以按照数据中心注册和发现服务,即支持只消费本地机房服务,使用多数据中心集群还可以避免单数据中心的单点故障。
- Raft算法: Consul使用Raft算法实现集群数据一致性。
通过Consul可以管理服务注册与发现,接下来需要有一个与Nginx部署在同一台机器的Agent来实现Nginx配置更改和Nginx重启功能。
有Confd或者Consul-template两个选择,而Consul-template是Consul官方提供的。其使用HTTP长轮询实现变更触发和配置更改(使用Consul的watch命令实现)。也就是说,我们使用Consul-template实现配置模板,然后拉取Consul配置渲染模板来生成Nginx实际配置。
参考
《Using nginx as HTTP load balancer》官网
《使用nginx实现HTTP负载均衡》 翻译官网
《亿级流量网站架构核心技术(负载均衡与反向代理)》
《Nginx负载均衡(七层)》