主要参考:
《大数据日知录》
https://zhuanlan.zhihu.com/p/34985026
什么是哈希分片
后台随着数据规约的越来越大,单机明显无法存储着庞大的数据量,只能依靠大规模集群在对数据进行存储和处理,所以系统的可扩展性也成为了很重要的一个点。
目前主流的大数据存储于计算系统通常采用横向扩展的方式支持系统的可扩展性,即通过增加机器数量来获得水平扩展能力。与此对应,对于待存储处理的海量数据,需要通过数据分片来将数据进行切分分配到各个机器中去。而哈希分片就是数据分片中很重要的一种。
本文涉及的哈希分片有三种:哈希取模法、虚拟桶、一致性哈希。
哈希取模法
假设有K台物理机,通过以下哈希函数可实现数据分片:
H(key)=hash(key) mode K
根据求出来的结果来决定存储到哪台物理机上。
这一种分片方式实现起来非常简单,但是缺乏灵活性,比如新增一台物理机到集群,哈希函数就变成了如下:
H(key)=hash(key) mode (K+1)
按照这样哈希函数来算,之前的数据和物理机之间的映射就全部被打乱,所有数据需要重新按照改变后的哈希函数再分配一遍。
虚拟桶
《大数据日知录》中以Membase数据库举例,如下图。
有以下几个关键单:
- 引入了虚拟桶层,所有数据通过哈希函数存储到对应的虚拟桶,一个虚拟桶会存多条数据。
- Membase通过内存表来管理物理机与虚拟桶的映射,一个物理机可以对应多个虚拟桶。
- 当加入新机器时,只需要改变虚拟桶和物理机的映射表就能实现扩展。
一致性哈希
关键点:
- 一致性哈希将哈希数值空间按照大小组成一个首尾相接的环状序列。(哈希数值空间范围为0~2^m,在下图中m=32)
- 对于每台机器,可根据其IP和端口号经过哈希函数映射到哈希数值空间内。
- 每个机器节点记录环中的前驱节点和后继节点位置,这样就变成了一个真正的有向环。
例如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:
数据路由
数据路由:数据分片后,能够找到某条记录的存储位置的方式。
由上面得知,一致性哈希的物理机形成了一个有向环,那么如何通过数据的key来知道存储到哪一台机器上呢?
最直观的方式就是讲key带入哈希函数计算出结果,然后沿着有向环顺序查找。对于物理机来讲,首先判断是否在自身管理范围内,如果不在就将它转交给后集节点继续查找。
这种方式是可行的,但是明显是一种很低效率的查找方式,多台物理机之间反复的通信将会消耗极大的资源,我们应当在尽量少的查找次数中找到应该存储的物理机。
因此,为了加快查找速度,一致性哈希就在每个物理机上配置了路由表。
路由表中配置了每一个节点的位置,因此当物理机发现要增添的数据不在自己管理的范围内的时候,就去路由表中查询该范围对应的物理机,然后交给该物理机去处理。
删除节点
正常离开:
将自身数据迁移到后继节点上,前驱节点和后继节点直接相连。
异常离开:
切换到该物理机的从机上。
新增节点
新增节点从理论上讲主要有两个步骤:
- 将新增节点加入有向环,有其自己的前驱节点和后继节点。
- 数据的重新分布,将原来应该由新节点存储的数据迁移到新节点上。(这个过程由所有节点自动完成,称为稳定性检测,每个节点会定期执行)
实际操作可以分为三个步骤,《大数据日知录》中的例子如下:(下图来自于《大数据日知录》)
假设目前有N5和N14两个节点,需要加入N8节点。
在N8加入之前,N5负责0 ~ 5的节点,N14负责6 ~ 14的节点
在N8加入之后,N5负责0~5的节点,N8负责6 ~ 8的节点 ,N14负责9 ~14的节点。
1、N8前驱节点连接null,后继节点连接N14。(这样便能触发稳定性检测)
2、通过稳定性检测,N14的前驱节点连接了N8,N14将6 ~ 8的节点迁移到N8。
3、N5连接N14的前驱节点,也就是N8。至此N9已经加入了有向环。
虚拟节点
每个物理机在哈希空间的位置取决于“IP和端口通过哈希函数计算的结果”,导致机器节点在哈希空间的位置是随机的,因此无法做到负载均衡。
如下图所示,A明显比B存储了更多的值。
为了解决这种数据倾斜问题,一致性Hash算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。
具体做法可以在服务器IP或主机名的后面增加编号来实现。如下图所示:
虚拟节点也不仅仅能解决负载均衡的问题。
实际操作中,机器的异质性很常见,既有高性能、高配置的机器,也有低配置的机器。使用虚拟节点,就可以让高配置的机器多管理一些数据,低配置的机器少管理一些数据。