https://www.jianshu.com/p/b8ae27cf22a9 突然想明白 其实网易的将军令 就是一个一致性哈希的玩法
关于一致性哈希算法在游戏服务器端的思考
需求分析
引入一致性hash算法
算法主要参考:dubbo ConsistentHashSelector 并做部分修改
算法测试
a. 初始运营服5个,每个服10w注册,即50w注册。后端一个node承载1w,后端初始50个node
算法步骤
- 初始化50w个rid,rid格式 serverId_id,shuffle
- build hash ring,replicaNumber(虚拟节点) = 160
- 依次遍历shuffle后的rid list,从hash ring select
- 看node整体分布情况(最大、最小、平均、标准差)
- 不断调整虚拟节点数目
统计结果展示
[7743, 8777, 8847, 8932, 8985, 9100, 9185, 9229, 9274, 9308, 9330, 9478, 9625, 9638, 9660, 9697, 9699, 9728, 9748, 9791, 9794, 9847, 9904, 10021, 10053, 10055, 10063, 10073, 10257, 10258, 10263, 10291, 10356, 10374, 10376, 10486, 10519, 10521, 10581, 10620, 10628, 10678, 10719, 10783, 10790, 10837, 10859, 11001, 11120, 12099]
replica:160 |max:12099|min:7743|mean:10000.0|std:750.9|median:10054.0[9142, 9393, 9518, 9525, 9549, 9578, 9626, 9659, 9667, 9690, 9765, 9777, 9811, 9831, 9848, 9850, 9886, 9889, 9909, 9933, 9940, 9958, 9998, 10002, 10007, 10029, 10030, 10050, 10052, 10129, 10152, 10158, 10182, 10184, 10202, 10212, 10213, 10215, 10247, 10265, 10273, 10279, 10297, 10321, 10322, 10342, 10358, 10420, 10456, 10861]
replica:1280 |max:10861|min:9142|mean:10000.0|std:317.2|median:10018.0
结论
- 在节点不动态变化的情况,算法可以保证同一个rid每次都select到同一个node
- 通过调整replicaNumber,可以让node负载相对均匀
- 因为rid样本是可确定的,所以可以这种方式不断调整hash ring的参数,来符合实际的负载情况,即是可预测的
- 如果一个node负载是1w,那么目前会有node overloaded。实际可以考虑将node负载调整为9k
b. 从a的结果上看,看似很美好,比较好的满足我们的需求,but 我们还要考虑新增/减少节点的情况
假设
让我们问问题先简化一下
因为我们本身是长连接,所以假设之前的50w个rid全部连接到已知的50个node需求:准备开始开第6个服,在新增10个node,用来承载10w人,并重建hash ring
测试输出
// 这个是已经连接的50个node的数据分布情况,和a的结果一致,也验证了本身一致性hash算法的正确性
[9142, 9393, 9518, 9525, 9549, 9578, 9626, 9659, 9667, 9690, 9765, 9777, 9811, 9831, 9848, 9850, 9886, 9889, 9909, 9933, 9940, 9958, 9998, 10002, 10007, 10029, 10030, 10050, 10052, 10129, 10152, 10158, 10182, 10184, 10202, 10212, 10213, 10215, 10247, 10265, 10273, 10279, 10297, 10321, 10322, 10342, 10358, 10420, 10456, 10861]
replica:1280 |max:10861|min:9142|mean:10000.0|std:317.2|median:10018.0
// 这个是新增10个node后的数据分布情况
[1499, 1534, 1569, 1652, 1673, 1675, 1684, 1712, 1713, 1723, 10585, 10948, 11119, 11162, 11173, 11177, 11223, 11267, 11270, 11324, 11348, 11404, 11504, 11511, 11530, 11546, 11547, 11569, 11570, 11610, 11631, 11635, 11674, 11681, 11684, 11706, 11742, 11750, 11758, 11769, 11796, 11815, 11842, 11855, 11878, 11908, 11912, 11921, 11933, 11952, 11991, 11996, 12019, 12068, 12068, 12077, 12089, 12157, 12215, 12657]
replica:1280 |max:12657|min:1499|mean:10000.0|std:3783.8|median:11620.5
结论
- 我们在假设条件成立的情况下,我们期望新增的10w客户端全部负载到新的10个node上。但是从结果上看,其实是负载了整个的60个node上(这个其实也是相对均匀的)。这个和我们预期完全不相符
- 从一致性hash的算法实现上看,对于新增/减少节点来说,一定是会有一部分客户端重新分配节点,这个是由算法本身决定的
继续沿着一致性hash的思路走
再换一个思路 假如我们把连接和数据分开呢?
ref