1. 困惑:consistent hash真的很好吗?
一直很好奇为啥讲consistent hash的博客到处都是,但是真正做关系库分库分表的时候,没见到有人用consistent hash(一般都是预先做好固定数量的分表,比如一开始就按uid后3位把某个表分成1000个子表,然后根据节点数去分这1000个子表),只见过有的nosql做自动sharding用这个算法(比如cassandra)。
当然lb领域也有很多一致性hash的轮子,曾经见到有文章里讲,他们为了保证请求黏性用了一致性hash作为lb算法,但个人觉得这完全没必要:真要保证请求黏性的话,先随机、然后在请求的cookie里打标就行了。
久而久之,自然产生困惑:这东西真有说的那么好么?真这么好咋没见人在分表的时候用上?
2. cassandra在使用consistent hash做sharding时遇到的问题
刚好看到DDIA里讲到一致性hash在新增节点时可能有分配不公平的问题,cassandra 3.0还专门设计了个算法解决这个问题,觉得很有意思。文中说:
![](https://img.haomeiwen.com/i8926363/8c10ddb665c7df54.png)
p209:
![](https://img.haomeiwen.com/i8926363/3bb16d30d3e4c147.png)
DDIA里只是抛出了这个结论,没解释为啥,带着疑惑我去看了下cassandra的博客https://www.datastax.com/blog/new-token-allocation-algorithm-cassandra-30
![](https://img.haomeiwen.com/i8926363/15214d599e8e8767.png)
大意是说随着节点数增多,理论上不成比例现象也会越来越多(严重),而且一旦出现了就不好修复。
个人推测的原因:
- 一方面,每次sharding不能保证100%均匀分配,那么sharding次数多了,不成比例就会有复利效应;
- 另一方面,随机算法一般给出的数学分析都是数学期望值,或者说是算法在average case下的表现,随机算法不能保证worst case情况下还能均匀分布,而worst case一旦出现,以后就基本不可逆了,产生“滚雪球”效应
3. 解决不公平问题的算法
那么怎么解决这个问题?仔细想想,这其实是个规划问题(或者说最优化问题),可以把随机算法换成确定性的规划算法。cassandra 3.0搞了一个很有意思的贪心算法:
![](https://img.haomeiwen.com/i8926363/91058266cbcd4f86.png)
![](https://img.haomeiwen.com/i8926363/984479d283478cb5.png)
个人理解的意思是:每次新加节点时,把所有已有的vnode的中点作为候选token,然后问题转化成:从这些候选token选择k个,使得分配后的负载尽量均匀,问最优化的选择方案是啥?“分配均匀”可以通过标准差这个指标来判断。
于是就可以用贪心/dp来解决了,当然cassandra加了一些规则,考虑机房、机架之类的因素。
具体实现没细看
4. consistent hash的其他问题
4.1. 迁移过程中的脏读问题
4.1.1. 问题描述
典型的例子是注册中心用一致性hash做数据分片,节点成员变化时要数据迁移,迁移的过程中如果客户端应用读服务数据,或者注册中心触发了回调通知,那么客户端会脏读,拿到的只是迁移过程中的一部分数据,效果就是客户端只会调这几台机器的服务,会瞬间让这几台机器过载、服务不可用。
4.1.2. 解决思路
本质上要实现事务
a. 手动关掉订阅通知功能,等迁移完了,再把订阅通知功能打开。相当于人肉做了一次事务写
但缺点是必须得锁定发布平台。因为:
- 过程中如果新应用发布,要查询,还是会查到脏数据,所以必须锁定发布平台、不让发布
- 应用刚好也在发布会导致服务发布失败、服务注册信息是缓存的旧的错误的数据
b. 实现事务写
4.2. 运维可控粒度太粗
总体来说就是缺乏运维可控性,不够“平滑”。很多领域特定应用有自己的特殊运维需求,用consistent hash不好灵活运维
(或者说,可控粒度太粗,有些运维场景希望可控粒度更细)
- 节点上下线时产生流量高峰
节点上下线时,数据迁移可能造成流量高峰,包括迁移完成后切流也没有限速、预热的过程 - 变更时难以控制影响面,包括
- 难灰度
比如:我们只迁移少量数据分片到新节点上的灰度试点
https://mp.weixin.qq.com/s/-5oK-EuZWpvIATvTzSMRAw - 不支持优先级
一些场景有优先级需求,比如注册中心使用一致性Hash做sharding,在节点上下线时,想优先让一些保障等级没那么高的接口做数据迁移,那么一致性hash不好做优先级划分。
解决的办法可能是在consistent hash上再加一层优先级算法,或者不用一致性hash,换成其他sharding策略
- 难灰度
网友评论