本文介绍了 Nginx 的负载均衡策略, 一致性 hash 分配原理, 及常用的故障节点的摘除与恢复配置.
分享者: 宜信支付结算八方数据团队高级技术经理 周恒
原文首发于支付结算技术团队公号: 野指针
前篇 Nginx 专题(1):Nginx 之反向代理及配置详细介绍了 Nginx 功能之一 -- 反向代理. 本篇文章将重点介绍 Nginx 功能之二 -- 负载均衡.
为了增加对负载均衡的好感, 我们先了解负载均衡能实现什么.
将多个服务器节点绑定在一起提供统一的服务入口.
故障转移, 在意外发生的时候, 可以增加一层保险, 减少损失.
降低上线运维复杂度, 实现平滑上线. 运维和开发同学都喜欢.
下面正式进入主题.
一, Nginx 的负载均衡策略
负载均衡就是将请求 "均衡" 地分配到多台业务节点服务器上. 这里的 "均衡" 是依据实际场景和业务需要而定的.
对于 Nginx 来说, 请求到达 Nginx,Nginx 作为反向代理服务器, 有绝对的决策权, 可以按照规则将请求分配给它知道的节点中的一个, 通过这种分配, 使得所有节点需要处理的请求量处于相对平均的状态, 从而实现负载均衡.
Nginx 支持的负载均衡策略很多, 比较重点的如下:
- round robin(轮询)
- random(随机)
- weight(权重)
- fair(按响应时长, 三方插件)
- url_hash(url 的 hash 值)
- ip_hash(ip 的 hash 值)
- least_conn(最少连接数)
这么多的策略, 非常不利于记忆和选择, 我们不妨将这些常见的策略归类, 分而化之, 方便挑选.
第一类 最佳实现
- weight(权重)
- random(随机)
最佳实践, 其实就是最常见, 最普通的默认配置, 当然也是在一定程度上最好用的配置. 不知道用什么方式的时候, 就可以选择用这一类型.
轮询不用多说. 这里的随机, 其实在大量请求的情况下, 按照概率的理论等同于轮询的方式.
轮询配置参考:
- # 默认配置就是轮询策略
- upstream server_group {
- server backend1.example.com;
- server backend2.example.com;
- }
随机配置参考:
- upstream server_group {
- random;
- server backend1.example.com;
- server backend2.example.com;
- server backend3.example.com;
- server backend4.example.com;
- }
第二类 性能优先
- weight(权重)
- fair(按响应时长, 三方插件)
- least_conn(最少连接数)
让业务节点中性能更强的机器得到更多请求, 这也是一个比较好的分配策略.
什么是性能更好的机器? 这个问题也有很多的维度去考量.
从经验或硬件上分为高权重, 低权重的机器.
按照节点请求的响应时长来决定是多分配请求, 还是少分配请求.
按照保持的连接数. 一般来说保持的连接数越多说明处理的任务越多, 也是最繁忙的, 可以将请求分配给其他机器处理.
权重的配置参考:
- upstream server_group {
- server backend1.example.com weight=5;
- #默认为不配置权重为 1
- server backend2.example.com;
- }
响应的时长 (fair) 配置参考: 需要在 Nginx 编译时加入 nginx-upstream-fair 模块.
- upstream server_group{
- fair;
- server backend1.example.com;
- server backend2.example.com;
- server backend3.example.com;
- server backend4.example.com;
- }
最少连接数 (least_conn) 配置参考:
- upstream server_group {
- least_conn;
- server backend1.example.com;
- server backend2.example.com;
- }
第三类 保持稳定
ip_hash
url_hash
很多请求都是有状态的, 上一次请求到哪个业务节点, 这次还要请求到哪台机器. 比如常见的 session 就是这样一种有状态的业务.
这里 Nginx 提供了按照客户端 ip 的 hash 来作为用户的标示分配, url 的 hash 作为分配标示的规则. 本质上还是要找到用户的请求中不变的要素, 抽离出来, 这样就可以进行分配了.
ip_hash 配置参考:
- upstream server_group {
- ip_hash;
- server backend1.example.com;
- server backend2.example.com;
- }
url_hash 配置参考:
- upstream server_group{
- hash $request_uri consistent;
- server backend1.example.com;
- server backend2.example.com;
- server backend3.example.com;
- server backend4.example.com;
- }
二, Nginx 支持一致性哈希进行分配
Nginx 支持一致性 hash 进行分配, 也就是配置中 consistent.
什么是一致性 hash? 为什么要引入这个机制? 在生产环境下, 业务节点经常会出现增加或减少的情况, 就算这种增加或减少都是被动的, 也可能会对 hash 分配产生影响. 如何能够做到尽量减少影响呢? 这时一致性 hash 被发明出来.
一致性 hash 解决两个问题:
分配特别不均匀;
节点变动除了对分配到这个节点上的请求有影响, 还会导致其他节点上的请求重新分配.
1)如何解决分配不均的问题
将原来的每一个节点复制出 N 个虚拟节点, 并且给这些虚拟节点都起个名字.
比如原来有 5 个节点, 分配的时候经常会不均匀, 现在每个节点都虚拟出 N 个节点, 就是 5*N 个节点, 会极大降低分配不均匀的情况. 下面就要说说如何分配的问题了.
2)如何解决节点变动的问题
一致性哈希的基本思想:
定义一个 [0,(2^32)-1] 的数值空间. 相当于取长度从 0 到 2^32-1 的线段.
节点映射到线段上. 将每个节点, 包括虚拟节点, 都通过 hash 算法得到数值, 然后映射到这个取值区间上.
如下图.
计算数据的 Hash 值. 把请求中的关键字符串通过 hash 算法得到一个数值, 在线段中找到一个位置, 如果算出来的数值大于 2^32-1 则认为是 0. 按照这个规则, 其实是把这个线段首尾相连形成一个环, 所以也叫 hash 环.
数据节点在线段上找归属的节点. 沿着这个线段向右找到离得最近的节点, 并把该节点作为这个数据的归属节点.
下面再来看节点的变化对一致性 Hash 的影响.
节点减少: 比如 NodeA 突然故障了, 原来分配到其他节点上的数据不会发生变化, 只有分配到 NodeA 上的数据会重新找离它们最近的点, 从而减少了 hash 重新分配的数量. 这也是一致性 hash 最大的优势.
节点增加: 比如现在请求量抖增, 需要增加节点降低负载. 当新加入节点 NodeE 时, NodeE 及它的一群虚拟节点会根据 hash 值分配在 hash 环上. 这时, 大部分数据再根据一致性哈希规则找其归属的 Node 节点都不会发生变化, 只有那些值计算出来发现离 NodeE 更近的数据发生了变化, 但数量毕竟是有限的, 减少了因为节点增加造成的影响.
三, 故障节点摘除与恢复
先看看经典配置, 再详细解释.
- upstream server_group {
- server backend1.example.com ;
- server backend2.example.com max_fails=3 fail_timeout=30s;
- server backup1.example.com backup;
- }
- max_fails=number
这个参数决定了多少次请求后端失败后会暂停这个业务节点, 不再给它发新的请求, 默认值是 1. 此参数需要配合 fail_timeout 一起用.
题外话: 如何定义失败, 有很多种类型, 这里因为主要处理 HTTP 代理, 所以更关注 proxy_next_upstream.
proxy_next_upstream: 主要定义了当服务节点出现状况时, 会将请求发给其他节点, 也就是定义了怎么算作业务节点失败.
fail_timeout=time
决定了当 Nginx 认定这个节点不可用时, 暂停多久. 不配置默认就是 10s.
把上面两个参数联合起来考虑就是: 当 Nginx 发现发送到这个节点上的请求失败了 3 次的时候, 就会把这个节点摘除, 摘除时间是 30s,30s 后才会再次发送请求到这个节点上.
backup
类似于 switch 语句中的 default, 当主要节点都挂了的时候, 会把请求打到这个 backup 节点. 这是最后一个救兵了.
四, 总结
由于 Nginx 采用了反向代理技术, 对于请求的转发有绝对的控制权, 使得负载均衡变成了可能.
本文介绍了负载均衡的概念, 详细分类了 Nginx 的负载均衡策略, 并提供了简单配置参考. 同时介绍了一致性 hash 的原理, 及常用的故障节点的摘除与恢复. 下一篇将会介绍 Nginx 功能之三 --HTTP 缓存, 敬请期待.
来源: https://segmentfault.com/a/1190000021266604