分布式存储
哈希取余算法
1、公式:hash(key) % N(机器台数),哈希值决定数据映射的节点
2、优点
(1)简单直接,负载均衡,分而治之
(2)只需预估节点数,就能保证一段时间的数据支撑,每台服务器固定处理一部分请求,并维护这些请求的信息
3、缺点
(1)每次数据变动导致节点有变动,映射关系需要重新进行计算
(2)扩容 / 缩容 / 故障停机,原取模公式变化,地址经过取余运算的结果变化,根据公式获取的服务器变得不可控
一致性哈希算法
1、一致性哈希环
(1)hash 函数产生 hash 值,算法的所有可能哈希值构成一个全量集,这个集合可以成为一个 hash 空间 [0, 232-1],是一个线性空间,但在算法中,通过适当的逻辑控制将它首尾相连(0 = 232),使它逻辑上形成了一个环形空间
(2)一致性哈希算法是对 232 取模,将整个哈希值空间组织成一个虚拟圆环
(3)如:假设某哈希函数 H 的值空间为 [0, 232-1](即哈希值是一个 32 位无符号整形),整个空间按顺时针方向组织,圆环的正上方的点代表 0,0 点右侧的第一个点代表 1,以此类推,直到 232-1,0 点左侧的第一个点代表 232-1, 0 和 232 在零点中方向重合,由 232 个点组成的圆环称为 Hash 环
2、服务器 IP 节点映射
(1)将集群中各个 IP 节点映射到环上的某一个位置
(2)将各个服务器进行哈希,具体可选服务器的 IP 或主机名作为关键字,确定每台机器在哈希环上的位置
3、落键规则
(1)存储一个 key-value 时,首先计算 key 的 hash 值:hash(key),即将 key 使用相同函数 Hash 计算出哈希值,并确定在环上的位置 A
(2)从位置 A 沿环顺时针查找,第一台服务器就是其应该定位的服务器,并将该键值对存储在该节点上
4、优点
(1)容错性:如果一台服务器不可用,则受影响的只是此服务器到其 Hash 环中逆时针方向的第一台服务器之间的数据,并转移到此服务器到其 Hash 环中顺时针方向的第一台服务器,其它不会受到影响
(2)扩展性:加入 / 删除节点只影响 Hash 环中顺时针方向的相邻节点,对其他节点无影响;数据量增加,需要增加一台节点 X,X 的位置在 A 和 B 之间,受影响的是 A 到 X 之间的数据,重新把 A 到 X 的数据录入到 X 上即可
5、Hash 环的数据倾斜问题
(1)一致性 Hash 算法在服务节点太少时,容易因为节点分布不均匀,而造成数据倾斜,被缓存对象大部分集中在某一台服务器上
(2)数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上,所以不能均匀分布存储数据
哈希槽算法
1、本质:数组 [0, 214-1] 形成 hash slot 空间
2、作用
(1)解决均匀分配问题:在数据和节点之间加入哈希槽,用于管理数据和节点之间的关系,节点存放槽,槽存放数据
(2)槽解决粒度问题:因为槽的数目固定,以槽为单位移动数据,变大粒度,方便数据移动
(3)哈希解决映射问题:使用 key 的哈希值计算所在槽,方便数据分配
3、hash slot 数量
(1)一个集群只能有 16384 个槽,编号 0 ~ 16383(0 ~ 214-1)
(2)这些槽会分配给集群中的所有主节点,分配策略没有要求,可以指定编号的槽分配到指定主节点,集群会记录节点和槽的对应关系
4、hash slot 数量为 16384 的原因
(1)CRC16 算法产生 hash 值有 16bit,即 216 = 65536 个值,值分布在 [0, 65535],取余不选择 65536,而选择 16384?
(2)心跳数据包的消息头有名为 myslots 的 char数组,长度为 16383 / 8,这其实是一个 bitmap,每一个位代表一个槽,如果该位为 1,表示这个槽是属于该节点
unsigned char myslots[CLUSTER_SLOTS/8];
(3)正常的心跳数据包带有节点的完整配置,可以使用幂等方式,以便更新节点的旧配置,这意味着它们包含原始节点的插槽配置,节点使用 16k 个插槽时,心跳数据包占用 2kb,但是节点使用 65k 个插槽时,心跳数据包占用 8kb
(4)同时,由于其他的设计权衡,Redis 集群不太可能扩展到 1000 个以上的主节点
(5)因此 16k 是一个合适的范围,在最多 1000 个主节点时,以确保每个主节点具有足够的插槽,但节点的插槽数量足够少,心跳数据包可以轻松地将插槽配置作为原始 bitmap 传播
(6)注意,在小型集群中,bitmap 将难以压缩,因为当 N 较小时,bitmap 将设置为 slot / N 位(N 表示节点数),这是一个很大的位设置比例
(7)在消息头中,最占空间的是 myslots[CLUSTER_SLOTS/8],当槽位数量为 65536 个时,心跳数据包的消息头占用:65536 / 8 / 1024=8kb,每秒钟发送的心跳包过于庞大,浪费带宽
(8)Redis 集群的主节点数量基本不可能超过 1000 个,集群节点越多,心跳包的消息体内携带的数据越多,如果节点过 1000 个,也会导致网络拥堵,因此不建议 Redis 集群节点数量超过 1000 个,对于节点数在 1000 以内的 Redis 集群,16384 个槽位足够使用
(9)Redis 主节点的配置信息中,通过 bitmap 保存槽位信息,bitmap = slots / N 位(N 表示节点数),在传输过程中,会对 bitmap 进行压缩,哈希槽位越少,节点越多,压缩率越低(更好)
5、hash slot 运算
(1)Redis 集群中内置 16384 个哈希槽,Redis 会根据节点数量,大致均等地将哈希槽映射到不同节点
(2)需要对 key 计算哈希值,然后对 16384 取余,余数为对应槽:slot = CRC16(key) % 16384
(3)当需要在 Redis 集群中放置一个 key-value 时,Redis 先对 key 使用 CRC16 算法,然后把结果对 16384 求余数,每个 key 都会对应一个编号在 0 ~ 16383 之间的哈希槽,即映射到某个节点上
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战