Nginx 学习笔记 (a4) - 浅谈负载均衡 (upstream)
Nginx 以高并发、低消耗而闻名,这个特点使其很适合作为一个负载均衡器 (Load Balancer),有策略地分发请求给不同的后端服务器。避免单点故障之余,亦增强整个系统的可用性,简单说不容易宕机。负载均衡是反代的其中一个用途。本文介绍 Nginx 常用的几个负载均衡策略。
⚠️ 假设有一组名为 backend 的 upstream,那么调用方式是 proxy_pass http://backend
。
热备 (Hot Standby)
在此例中,平时使用 www.example.com 提供服务,bad.example.com 则暂时下线,bak.example.com 作为发生故障时兜底的一台机器。又称故障转移 (failover)。
upstream backend {
server www.example.com;
server bad.example.com down;
server bak.example.com backup;
}
轮询 (round-robin)
介个是经(mò)典(rèn)的负载均衡算法。理论上会跳过不能用的 server,但预设的超时太长,实务上可改成 proxy_connect_timeout 1
、proxy_read_timeout 1
和 proxy_send_timeout 1
。
按照时间先后来分发请求。在此例中,顾名思义第 1 个 request 走 srv1.example.com,第 2 个走 srv2.example.com,第 3 个走 srv3.example.com,第 4 个走 srv1.example.com……以此类推。
upstream backend {
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
最小连接 (least-connected)
因应忙闲不均、负载不均的问题而生。在此例中,Nginx 将试图减轻已经很忙的服务器的压力,把新请求分发至没那么忙的主机。
若对动态负载均衡的算法感兴趣,还有一插件 nginx-upstream-fair 可以实现最快响应法。
upstream backend {
least_conn;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
源地址哈希 (ip-hash)
Session 用于跟踪用户操作,涉及身份认证时 (用户系统) 往往能派上用场,而通常情况下会话信息保存在单机上,这就使得有些需求得在同一台服务器上完成,不能换到其他的服务器 (姑且不谈分布式 Session)。
Sticky Sessions (粘滞会话) 将保证一个用户对应一台服务器,从而解决 Session 不一致的问题 (通常表现为无法登录)。出于容灾理由,不建议大量使用。
upstream backend {
ip_hash;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
加权负载均衡 (Weighted Load Balancing)
集群中难免有算力不均的情况。不同服务器处理速度有快有慢,不问性能的齐头式平等,很可能触发木桶原理的副作用——让配置最差的那个服务器决定整个服务器集群的性能。可跑一次 bench.sh,再依据测试结果给服务器排个序。
在此例中,每 10 个新请求有 6 个被分配至 srv1.example.com,然后各有 2 个被分配至 srv2.example.com 和 srv3.example.com。此例演示的轮询法,事实上最小连接和源地址哈希法也可以分配权重。
upstream backend {
server srv1.example.com weight=3;
server srv2.example.com;
server srv3.example.com;
}
运行状况检查 (Health Checks)
根据 Nginx 的文档,max_fails
缺省值是 1,fail_timeout
缺省值是 10s。
在此例中,www.example.com 的健康检查会被关闭,一直都标记为可用;www2.example.com 连不上时先重试 2 次,如果还不行就退出服务,下线 1 天,方便运维人员排障。
upstream backend {
server www.example.com max_fails=0;
server www2.example.com max_fails=2 fail_timeout=1d;
}
关于指令 proxy_next_upstream
根据 Nginx 的文档,proxy_next_upstream
含括下列数种情况:
error
建立连接 / 发送请求 / 接收响应时出错(缺省值之一);timeout
建立连接 / 发送请求 / 接收响应时超时(缺省值之一);invalid_header
上游返回空白或无效响应;http_500
上游返回 500 Internal Server Error;http_501
上游返回 501 Not Implemented;http_502
上游返回 502 Bad Gateway;http_503
上游返回 503 Service Unavailable;http_504
上游返回 504 Gateway Timeout;http_404
上游返回 404 Not Found;http_429
上游返回 429 Too Many Requests;non_idempotent
解除对非幂等请求 (POST, LOCK, PATCH) 的封印,小心造成重复提交;off
不得转给下一台服务器。
一般来说,即使某一台后端服务器返回了 500,这台服务器也会参与负载均衡,毕竟能收到 HTTP 状态码,就表示它还活着。但这样的结果在用户眼里跟 Connection Refused 以及 Operation Timed Out 可没啥区别,所以在此例中,把 500 一并纳入“在下一台服务器重试”的机制里。
location / {
...
proxy_pass http://backend;
proxy_next_upstream error timeout http_500;
...
}