《SRE google 运维解密》读书笔记 (六)
负载均衡
前端
使用 DNS 进行负载均衡。在 DNS 回复中提供多个 A 记录或者 AAAA 记录。
虽然 DNS 看起来简单,但是存在不少问题。
- DNS 对客户端行为的约束很弱:记录是随机选择的。
- 客户端无法识别“最近”的地址
- 权威服务器不能主动清楚某个解析器的缓存,DNS 记录需要保持一个相对低的失效值(TTL)。
需要在 DNS 负载后面增加一层虚拟 IP 地址,我们常说的 VIP。
使用 VIP 进行负载均衡
虚拟 IP(VIP) 不是绑定在某一个特定的网络接口上的。很多设备共享。外界看 VIP 是一个独立的普通 IP。VIP 是网络负载均衡器。负载均衡器接收网络数据包,转发给 背后的某个服务器。
负载的方案:
- 对于无状态的服务,理论上说永远优先负载最小的后端服务
- 对于有转态的服务
- 某个连接标识取模
- 一致性哈希
后端
理想情况
某个服务的负载会完全均匀的分发给所有的后端服务。任何时间点,最忙和最不忙的任务消耗相同数量的 CPU。
识别异常任务
- 限流
- 客户端限流
- 某个后端的活跃请求达到一定数量,客户端将后端标记为异常转态,不再发送请求。
- 正常情况下,后端请求很快完成,限流几乎不会触发
- 后端过载了,请求响应慢,客户端就会自动避开这个后端
- 缺点就是,不精确。后端很可能达到限额之前就过载了。反之亦然。
- 坡脚鸭任务
- 客户端视角来看,后端任务有以下几个状态
- 健康
- 拒绝连接
- 坡脚鸭状态
- 后端服务正常,也能服务请求。但是明确要求客户端停止发送请求。
- 某个请求进入坡脚鸭状态,需要广播给客户端
- 处于停止过程中的服务不会给正在处理的请求返回错误
- 可以实现优雅的下线服务
- 客户端视角来看,后端任务有以下几个状态
利用划分子集限制连接池大小
子集划分:限制某个客户端任务需要连接的后端数量。
Google 的 RPC 框架对于每个客户端都会维持一个长连接。如果一个集群的规模过大,客户端就要维护很多长连接。
子集选择算法
- 随机选择
- 确定性算法
负载均衡策略
简单轮询
造成效果差的因素如下:
- 子集过小
- 请求处理的成本不同
- 物理服务器的差异
- 无法预支的性能因素
- 怀邻居(物理服务器上的其他进程)
- 任务重启
最闲轮询策略
客户端追踪子集中每个后端任务的活跃请求数量,在活跃请求最小的任务中进行轮询。
最危险的坑:如果一个任务不健康,可能 100% 返回错误。取决于错误的类型,错误回复可能延迟非常低。从而给异常任务分配的大量的请求。
需要将错误信息计算为活跃请求,剔除异常任务。
限制:
- 活跃的请求数量不一定是后端容量的代表
- 每个客户端的活跃请求不包括其他客户端发往同一个后端的请求
实践中发现,效果很差。
加权轮询
每个客户端为子集中的每个后端任务保持一个“能力”值。请求仍以轮询方式分发,客户端按照能力值权重比例调节。
实践中效果较好。