负载平衡算法
一些基本的负载平衡算法
以下算法,一般都只考虑节点负载的平衡,不考虑cache命中以及session维护
Round Robin / Random (weighted allowed)
- 特点
- 每个接受请求的概率相同(与权值正比)
- simple
- state
- fixed weight = stateless
- dynamic weight = 依赖权值计算的具体方法(可以根据连接数、响应时间、吞吐、内存、CPU等决定权值)
- 场景
- 每个处理节点性能差不多
- 期望低延迟路由,计算量小
Chained Failover
- 节点成链条,每次只有当前节点无法接受更多时,选择链条的下一个节点。
- 可以和主从备份相结合
基于某个资源最小的节点
- 共性: 有状态,需要节点个数
- 无中心化
- sender 去pull receiver的节点负载
- receivwe 去 push 负载到 sender
- 中心化
- 由中心监控节点负责路由和连接记录
- 可以弱加权: 连接数差不多时,选权值高的
- 无中心化
Least Connection 最小连接(active task)数
- 特点
- 优先发送给当前连接数最少的节点
- 往往需要对每个节点设置最大连接数
- 场景
- 每个连接(任务)开销差不多
The Least Response Time Method
- 特点
- 优先发送给最近响应时间内少的节点
- 场景
- 用于WAN下就近选择服务器,不适合LAN下极低响应的环境
The Least Bandwidth(Throughput) Method
- 特点
- 优先发送给最近一段时间内使用带宽最少的节点
The Least Packets method
- 特点
- 优先发送给最近一段时间内传输包最少的节点
一致性Hash - Memcached采用
本质:用DHT(distributed hash table)管理键值,原本的目的是在P2P网络中快速定位资源,但是也常用来做负载均衡
普通的Hash负载平衡
- 根据key(比如IP)对节点个数取模
- 优: 机器不变动时,缓存友好和便于维护session
- 缺点:机器变动时,导致IP和节点的映射变化,缓存命中率下降,IO增加
优雅地处理节点动态增减
- 目的: 为了使得原来的IP与节点映射关系变化尽量少
- 方法:对 $2^{32}-1$ 取模,得到hash环。 每个请求直接路由到顺时针下的那个节点。 插入和删除节点就是在环上增减点
- 减少: C节点宕机, 对象C从节点C变为D
- 增加: 增加D节点,对象C从节点C变为D, 一般是随机分配
几种维护节点的方法
- 链表:快改慢查, 每个节点记录前一个节点和后一个节点的位置信息
- 根据key查找节点: O(N) , N为节点数量
- 增删节点 : O(1)
幂次逼近,Chord系统采用: 每个节点都要维护一个大小为N(可以更小)的finger table。
- 查找节点: O(logN)
- 增删节点: O(logN), 可以只更新一个节点的finger table
- 容错:为防止某节点之后连续的节点失效,导致新加入的节点未加入,所以对于每个节点需要额外维护一个长度为r的后续节点表,比如r=1/2,只要不是连续有一半机器失效,就可以正常工作。
虚拟节点:Dynamo系统
去中心化,可以从任意一个节点请求,也可以从负载均衡器开始
一个实际物理节点对应多个虚拟节点
- 负载高的节点 减少虚拟节点
- 负载低的节点 增加虚拟节点
冗余容错:NWR策略
只要满足W+R > N(即W和R读取的数据必有重叠),就可以保证当存在不超过一台机器故障的时候,至少能读到一份有效的数据。如果应用重视读效率,可以设置W=N,R=1; 如果应用需要在读/写之间权衡,一般可设置成N=3, W=2, R=2。Dynamo推荐使用322的组合。
N:同一份数据备份的份数
W:是更新一个数据对象的时候需要确保成功更新的份数
R:读取一个数据需要读取的最少节点(备份)的份数数据版本管理: vector clock
- 只保证eventual consistency,写请求可以写更新所有节点前返回,这个时候get就可能得到旧版数据。
- 一旦数据之间发生了冲突不会丢失,但是可能会有已被删除的数据重新出现
- 这就会导致版本会出现分支,因为修改一个keyvalue时候,并不会阻塞,分支无法自动解决,需要人为定义merge方法。
传播节点增删协议: Gossip
- 不断传播信息到接触到的最多的节点。
如何达到负载均衡
问题
- 极端情况下的hash冲突
- 多节点管理维护成本还是较高的。
- DHT使得key变成散列,适合随机访问,如果存在顺序访问操作,还是B系列树结构比较合适
Hash槽 - redis采用
目的:为了避免高额的管理成本
取消了虚拟节点,每个物理节点管理一块连续的hash区域。
删除节点和增加节点方法和一致性hash一样
负载均衡方式改为调整槽的大小,而不是增加、减少虚拟节点个数
图示:一个 Redis Cluster包含16384(0~16383)个哈希槽,存储在Redis Cluster中的所有键都会被映射到这些slot中,集群中的每个键都属于这16384个哈希槽中的一个,集群使用公式slot=CRC16(key)/16384来计算key属于哪个槽
Reference
- https://kemptechnologies.com/load-balancer/load-balancing-algorithms-techniques/
- https://poweruphosting.com/blog/load-balancing-algorithms/
- https://my.oschina.net/freegeek/blog/334842
- https://zhuanlan.zhihu.com/p/34985026
- https://www.cnblogs.com/gnuhpc/archive/2012/01/13/2321476.html
- https://draveness.me/dynamo
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment