一致性哈希是数据分区的经典算法
分布式系统主要有两种手段解决单点故障:
- 数据分区: 例如有三台机器 id=7 的数据存储在 7%3=1 机器1 上
- 数据副本(业界实践至少三副本)
arangodb 两种方法都用上来解决单点故障+负载均衡问题
如果按照 id%num_nodes 的算法分区,一旦扩容缩容整个集群的 key->node 的映射会变,除非全部节点停止工作再重新编排所有数据
一致性哈希的思路是,将 ipv4 地址 u32 范围想象成一个环
集群 ip 经过特殊运算得到的哈希尽可能均匀分布在环上(当然会有 id 跟节点 ip 哈希冲突的缺点)
参考: https://segmentfault.com/a/1190000021199728
node(ip1) < node(ip2) <= id < node(ip3) 的数据会去 ip2 上面获取
一旦缩容量 ip2 不想要了直接全部数据迁移到 ip1 上,然后会找 hash(ip)<hash(key/id)
逆时针最近的数据节点 ip1
扩容也是同理
一致性哈希可能由于集群 IP 分布接近导致哈希结果不能均匀分布在环上,所以可以优化为一个节点内包含 100-200 个虚拟节点分布在环上去抑制不均匀
但分区不解决高可用 High Available 的问题,分区节点挂了相应的数据就全丢了
数据副本是分布式系统解决数据丢失异常的唯一手段
https://coolshell.cn/articles/10910.html
分布式系统的复杂在于不确定的 rpc 调用第三态 —— 成功/失败/超时
consistency, availability, partition tolerance(高可扩展性)
强一致性、高可用、数据分区性能好 三者只可能要两个,强一致性会(如两阶段提交,集群所有节点先预提交,集群协调器发现全部已预提交再回复正式提交,然后节点开始正式提交)导致分布式系统性能显著降低。所以分布式系统必须有所取舍了
分布式系统起码要满足高可用吧(A), NoSQL 一般追求 AP 而传统数据库追求 CA