余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

分布式 | DBLE 分片算法之 hash 分片

xiyangw 2023-09-16 15:05 16 浏览 0 评论

作者:赵红杰

DBLE 项目测试负责人,主导分布式中间件的测试,在测试中不断发现产品和自身的 bug。迭代验证,乐在其中。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。


背景

社区有大佬分享过跳增 hash 的文章,但是当时并不理解跳增 hash 使用的场景。

刚接触分布式数据库中间件 dble 的时候,最迷惑的概念之一是 hash 分片算法。

看到哈希,第一印象是散列表,感觉是存储相关的。hash 一个重要的特征是需要不同输入产生不同输出,但是在分片算法里,是需要多个值映射到一个分片节点上。这么大的差异,为什么可以用 hash 来对分布式数据库做逻辑分片,并且还命名叫 hash 分片!!!它们之间有哪些神似呢?


概念

散列表

要理解他们之间的相似和差异,先从对 hash 最初的认识——散列表说起。

散列表是一种数据结构,通过散列函数(也就是 hash 函数)将输入映射到一个数字,一般用映射出的数字作为存储位置的索引。

数组在查找时效率很高,但是插入和删除却很低。而链表刚好反过来。

设计合理的散列函数可以集成链表和数组的优点,在查找、插入、删除时实现 O(1) 的效率。散列表的存储结构使用的也是数组加链表。执行效率对比可以看下图 1.3:





散列表的主要特点:

1. 将输入映射到数字

2. 不同的输入产生不同的输出

3. 相同的输入产生相同的输出

4. 当填装因子超过阈值时,能自动扩展。

填装因子 = 散列表包含的元素数 / 位置总数,当填装因子 =1,即散列表满的时候,就需要调整散列表的长度,自动扩展的方式是:申请一块旧存储容量 X 扩容系数的新内存地址,然后把原内存地址的值通过其中的 key 再次使用 hash 函数计算存储位置,拷贝到新申请的地址。

5. 值呈均匀分布。

这里的均匀指水平方向的,即数组维度的。如果多个值被映射到同一个位置,就产生了冲突,需要用链表来存储多个冲突的键值。极端情况是极限冲突,这与一开始就将所有元素存储到一个链表中一样。这时候查找性能将变为最差的 O(n),如果水平方向填充因子很小,但某些节点下的链表又很长,那值的均匀性就比较差。


hash 分片

理解了散列表的基本特点,再来看看分布式数据库的 hash 分片。

hash 分片设计的要点:

1. 固定的数据映射到固定的节点 / 槽位

2. 数据分布均匀

3. 扩容方便

主要是扩容时尽可能移动较少的数据。扩容之后实现新的数据分布均匀。

想要实现动态扩容,尽可能不影响业务并保证效率,需要做到移动尽可能少的数据,一致性 hash 就是为了解决移动较少数据的问题,但是一致性 hash 的缺点是数据分布的均匀性较差。为了解决这个问题,聪明的 dev 们又设计了跳增一致性 hash 算法。

到这里,可以看出 hash 与分片最紧密或者说最神似的点在于:

1. 固定的输入有固定的输出

2. 值呈均匀分布

如果分布式数据库的分片数据分布不均匀,最糟情况就像散列表的极端冲突一样,落在最终数据库上的压力跟不使用分布式相同。

3. 方便扩容

当分片填充满的时候,需要扩容使总数据量在总分片之间再次达到数据均匀分布状态,扩容需要用 hash 函数重新映射旧值到新的分片。

4. 散列表和 hash 分片想要有好的表现都依赖于设计良好的 hash 函数。

正是由于这些相似特点,Hash 在分布式数据库里得到比较多的使用。回到测试的老本行,这些点便是我们测试思考的重点。

了解了分布式与 hash 的关联,再来八几句 hash 函数,可以说hash函数设计的好坏,直接决定了分片策略是否合适。

一致性 hash 和跳增 hash,大家参考社区相关文章:

https://opensource.actionsky.com/20190910-dble/


hash 取模分片

还有一种比较简单的 hash 函数是取模 hash。目前的分布式数据库基本都提供了这种分片支持。主要业务场景是:分片键的值存在单调递增或递减、分片键的值不确定,基数大且重复的频率低、需要写入的数据随机分发、数据读取随机性较大。

取模 hash,举个最简单的例子就能明白:分片数设置为 2,要把数据均匀分布在这 2 个分片上,直接对分片 key 取模 2,这样模值为 0 的数据落在分片 1,模值为 2 的数据落在分片 2。只要输入的数据奇偶均匀,分片数据就保证均衡。

取模 hash 在 dble 里还做了一些变种支持,比如可以指定每个分片的连续值的数量,比如自然数 0-99 放分片 1,自然数 100-599 放分片 2,具体配置方式参考官方文档。这样做主要目的是改善 hash 在范围查询时的效率问题。

Hash 取模分片非常简单,均衡性比较好,能分散数据热点,并且能快速人为识别数据所在分片。缺点也很明显。

1. 在业务上范围查询效率比较低

2. 扩容不便

因为取模 hash 强依赖于分片数,当新增或删减分片节点——即扩缩容时,大量的数据在重新映射后都需要挪动。比如上面的 2 分片数据,如果增加到 3 分片,原来分片 1 上的数据只有 1/3 的数据可以保留不动,另外 2/3 的数据都需要挪到新的分片上,分片 2 也是如此。

如果真的使用了 hash 取模分片,为了后期在扩容时移动尽可能少的数据,dble 的建议是:取模的基数不能大于 2880,原因是:2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 30, 32, 36, 40, 45, 48, 60, 64, 72, 80, 90, 96, 120, 144, 160, 180, 192, 240, 288, 320, 360, 480, 576, 720, 960, 1440 是 2880 的约数。

以上是对分布式与 hash 的一些浅显认识,文章内容部分来自对书或互联网知识的个人理解,不当之处欢迎指正。

Ref:

1. 《图解算法》

2. 《分布式系统常用技术及案例分析》

3. https://actiontech.github.io/dble-docs-cn/1.config_file/1.05_sharding.xml.html

4. https://tech.antfin.com/docs/2/99411

相关推荐

数控系统常见术语详解,机加工人士必备资料
数控系统常见术语详解,机加工人士必备资料

增量编码器(Incrementpulsecoder)回转式位置测量元件,装于电动机轴或滚珠丝杠上,回转时发出等间隔脉冲表示位移量。由于没有记忆元件,故不能准...

2023-09-24 17:42 xiyangw

功、功率、扭矩的关系

功=功率×时间work=power×timeW=P×T功=力×距离work=force×lengthW=F×LP×T=F×LP=F×L/T=F×V(velocity)具体到电机输出轴上,圆...

Wi-Fi协议(802.11 )常见专业术语汇总
Wi-Fi协议(802.11 )常见专业术语汇总

Wi-Fi协议(802.11)常见专业术语汇总AP(Accesspoint的简称,即访问点,接入点):是一个无线网络中的特殊节点,通过这个节点,无线网络中的...

2023-09-24 17:41 xiyangw

不需要策略模式也能避免满屏if/else
不需要策略模式也能避免满屏if/else

满屏if/elsejava复制代码publicstaticvoidmain(String[]args){inta=1;if...

2023-09-24 17:41 xiyangw

喜极而泣,我终于干掉了该死的 if-else
喜极而泣,我终于干掉了该死的 if-else

推荐阅读:面试淘宝被Tomcat面到“自闭”,学习这份文档之后“吊打”面试官刷完spring+redis+负载均衡+netty+kafka面试题,再去面试BAT...

2023-09-24 17:40 xiyangw

Python中使用三元运算符简化if-else语句
Python中使用三元运算符简化if-else语句

Python是一种极简主义的编程语言,相比其他编程语言,在多个地方简化了代码的写法,可以让我们用更少的时间更简洁地完成工作。以赋值运算符为例:a=a+b简化...

2023-09-24 17:40 xiyangw

雅思课堂 | 雅思口语写作句型第二讲
雅思课堂 | 雅思口语写作句型第二讲

纯干货,无废话用最少的时间学最制胜的内容!泡图书馆泡不过学霸?碎片时间也能弯道超车!向着雅思8分行动起来吧!雅思口语写作句型1.Ipreferseeing...

2023-09-24 17:39 xiyangw

设计模式(三)——简单的状态模式代替if-else
设计模式(三)——简单的状态模式代替if-else

博主将会针对Java面试题写一组文章,包括J2ee,SQL,主流Web框架,中间件等面试过程中面试官经常问的问题,欢迎大家关注。一起学习,一起成长。前言大多数开...

2023-09-24 17:38 xiyangw

如何优化代码中大量的if/else,switch/case?

前言随着项目的迭代,代码中存在的分支判断可能会越来越多,当里面涉及到的逻辑比较复杂或者分支数量实在是多的难以维护的时候,我们就要考虑下,有办法能让这些代码变得更优雅吗?正文使用枚举这里我们简单的定义一...

优秀程序员早就学会用“状态模式”代替if-else了
优秀程序员早就学会用“状态模式”代替if-else了

2020年已经进入倒计时了,大家立好的flag完成了吗?2020实“鼠”不易,希望2021可以“牛”转乾坤。简介状态模式是行为型设计模式的一种。其设计理念是当对...

2023-09-24 17:37 xiyangw

用Select Case语句对执行多条件进行控制
用Select Case语句对执行多条件进行控制

今日的内容是"VBA之EXCEL应用"的第六章"条件判断语句(If...Then...Else)在VBA中的利用"。这讲是第三节...

2023-09-24 17:37 xiyangw

c#入门教程(四)条件判断if else

条件判断,是编程里常用的判断语句,比如某个代码如果满足条件就执行a代码块否则就执行b代码块。案例1:inti=2*5;if(a>0){执行a代码块}elseif(a<0){执行b代码块...

每日学编程之JAVA(十一)—条件语句(if……else)

一个if语句包含一个布尔表达式和一条或多条语句。如果布尔表达式的值为true,则执行if语句中的代码块,否则执行if语句块后面的代码。if语句后面可以跟else语句,当if语句...

不需要策略模式也能避免满屏if/else

除了使用策略模式以外,还可以使用其他设计模式来避免满屏if/else的问题。以下是一些可能的解决方案:工厂模式:将if/else语句移到工厂类中,由工厂类负责创建对象。这样可以将if/else语句从客...

围绕ifelse与业务逻辑的那些梗
围绕ifelse与业务逻辑的那些梗

ifelse很重要,几乎是程序员编程核心,业务逻辑与规则也通过ifelse体现出来,语句简单但是背后文章很大,先看几则幽默图:1.也许默认使用returnf...

2023-09-24 17:36 xiyangw

取消回复欢迎 发表评论: