文章目录
1. 整体介绍
在数据量激增的今天,单机无法存储与处理PB及以上规模的数据量,需要依靠大规模集群对数据进行存储和处理,所以系统的可扩展性作为衡量系统优劣的重要指标。
目前主流的大数据存储与计算系统通常采用的是横向扩展方式来支持系统的可扩展性,对于待存储处理的海量数据,需要通过数据分片来将数据进行切分到并分配到机器中,数据分片后,如何找到存储的对应位置,我们称之为数据路由
。
数据分片与数据复制是紧密联系的,对于海量数据,通过数据分片来实现的系统的水平扩展,通过数据复制来保证数据的高可用性。同时为了保证数据在系统故障情况下仍然可用,需要将同一份数据复制存储在多个地方来确保数据可用。数据复制可以增加读操作的效率,客户端可以从多个复制的数据中选择物理距离较近的进行读取,增加了读操作的并发性,还能提高单次读取效率。
下图展示了数据分片与数据复制的关系
:
2. 抽象模型
下图为一个抽象级别的数据分片与路由的通用模型
:
我们可以将其看成一个二级映射关系,第一级映射是key-partition
映射,它将数据记录映射到数据分片空间,映射关系是多对一,即一个数据分片包含多条记录数据;第二季映射是partition-machine
映射,它将数据分片映射到物理机中,一般也是多对一映射关系,即一台物理机容纳多个数据分片。
做数据分片时,根据key-partition
映射关系将大数据水平切割成众多数据分片,然后按partition-machine
映射关系将数据分片放置到对应的物理机器上。
做数据路由时,要查询某条记录的值Get(key)
,根据key-partition
映射找到对应的数据分片,然后再查找partition-machine
关系表,查询到哪台物理机存储了这条数据,就可以根据key
读取对应value
的值了。
3. 哈希分片
一般使用哈希函数进行数据分片,下面对常用的三种哈希分片方式分别是:Round Robin、虚拟桶、一致性哈希方法,下面分别进行详细的介绍。
3.1 Round Robin
Round Robin 俗称哈希取模,是比较常用的数据分片方法,假如有k台物理机,通过哈希函数可以实现数据分片:
H(key) = hash(key)mod k
将物理机从0
到k-1
进行编号,根据上述哈希函数,对于以key
为主键的某个记录,H(key)
的数字即是存储该数据的物理机编号,这样就能将所有的数据分配到k
台物理机上,查找是也使用同样的哈希函数找到存储数据所在的物理机。
这个方法的优点就是实现简单,但缺乏灵活性,如果在分布式系统中新增1台物理机,哈希函数就变成了:
H(key) = hash(key)mod(k+1)
如果这样的话,之前的分配的数据与存储数据物理机的映射关系全部被打乱,需要按新的哈希函数重新分配一次。
造成缺乏灵活性的原因是,前面介绍的数据分片与路由的抽象模型可以看出,实际上 Round Robin 是将物理机和数据分片这2个功能合并了,这样使得映射函数和机器无法解耦。
3.2 虚拟桶
Couchbase
是一个内存分布式NoSQL
数据库,对于数据分片管理,他们提出了虚拟桶的实现方式,运行机制
如下:
在存储记录和物理机之间引入虚拟桶层,记录先通过哈希函数映射到对应的虚拟桶,然后才是虚拟桶和物理机之间的映射关系,通过表格管理来实现。
相对 Round Robin 来说,虚拟桶将原来的单层映射调整为二级映射,提高了扩展性,新的物理机加入时,只需要调整第二级partition-machine
映射表中收到影响的个别条目即可实现扩展,灵活性更强。
3.3 一致性哈希
分布式哈希表(DHC)是P2P网络和分布式存储中的常见技术,是哈希表的分布式扩展,考虑在多台物理机的分布式环境下,如何通过哈希方式来对数据进行增/删/改/查等数据操作的方法。而一致性哈希,就是DHC这种技术概念的一种实现方式,本节主要介绍Chord系统中提出的一致性哈希算法。
下图将哈希空间表示为长度为25的一致性哈希算法示意图(m=5),哈希空间可表达的范围是 0~31 ,算法将哈希数值空间按大小组成一个首尾相接的环状序列。每台机器按IP与端口号,经过哈希函数映射到哈希数值空间内,图中的5个节点代表不同的机器,分别用Ni表示,其中i表示其哈希空间对应的数值,比如N14节点存储主键经过哈希后落在 6~14 范围内的键值数据,每个机器节点记录环中的前驱节点和后继节点地址位置,形成一个真正的有向环。
路由表
根据以上方式完成构建后,在P2P环境下无中心管理节点,那如何进行查询呢?最直观的方式是沿着有向环顺序遍历所有的机器节点Ni进行查询,但是这是一种低效的查询方式,为了加快查询速度,可以在每个机器节点配置路由表,路由表存储m条路由数据,第i项路由信息代表距离当前节点为2i的哈希空间数值所在的机器节点编号,例如上图中N14节点,对应路由表如下:
距离 | 1 (20) | 2 (21) | 4 (22) | 8 (23) | 16 (24) |
---|---|---|---|---|---|
机器节点 | N20 | N20 | N20 | N25 | N5 |
一致性哈希路由算法
有了路由表,可以使用一致性哈希路由算法来进行查询。
算法思路:通过不同节点之间发送消息来协作完成,假设当前执行操作的节点为Nc,其初始值是Ni,Nc的后继节点为Ns。
步骤1
:判断是否c<j<=s
,如果为真,结束查找,Nc发送消息给Ns查找key值对应的value,Ns将查询结果返回给Ni(每个消息都包含消息源Ni的相关信息)。
步骤2
:当步骤1结果为假,Nc查找其对应路由表,找到小于j的最大编号节点Nh,Nc向Nh发送消息,请求它代表Ni查找key值对应的value,Nh此时成为当前节点Nc,继续按步骤1和步骤2递归查询。
举例说明:如下图,在N14节点查到key的键值请求,H(key)=27
,根据算法步骤1,N14发现27不在后继节点N20中,进入步骤2,查询路由表,找到小于27的最大编号节点N25,发送请求给N25,查找key的键值,N25进入算法的步骤1,发现27落在后续节点N29上面,于是发送请求给N29,让N29查询,N29查询完成后,将对应的值返回给N14完成查询,为什么返回给N14呢?因为上面提到过每个消息都包含消息源N14的信息。
根据这个示例,能够看出一致性哈希路由算法的查找过程类似一个二分查找。
节点新增
如果需要在P2P网络中新加入1个机器节点Nnew,需与任意一个节点建立联系,例如Nx,根据Nx的路由算法查询Nnew对应的哈希值Hash(Nnew)=new,找到Nnew的后继节点Ns,设Ns的前驱节点为Np,为了让Nnew加入P2P网络,就必须重新建立它们之间的p2p网络架构关系。
在非并发情况下
,执行以下2个步骤:
step1
. 改变Np、Nnew、Ns对应已经发生改变的前驱、后继节点记录;
step2
. 数据重新分片和分布,将Ns中存储的应该由Nnew承载的数据迁移到Nnew上;
在并发情况下
,为了确保数据的正确性,需要完成以下2个步骤:
step1
. 将Nnew的后继节点指向Ns,前驱节点指向null;
step2
. 进行周期性的稳定性检测,P2P网络中每个节点会定期执行,通过这个步骤完成前驱和后继节点的更新和数据迁移,但这并不是专门为新加入节点准备的;
稳定性检测算法
算法思路与流程:
step1
.假设Ns为Nc的后继节点,Nc向Ns询问前趋节点Np;
step2
.如果Np介于Nc和Ns之间,Nc记录Np为它的后继节点;
step3
.令Nx为Nc的后继节点,其有可能是Ns或者Np,这得看前一步, 如果Nx的前趋节点为 null 或者 Nc位于Nx和 它的前趋节点之间,那么 Nc就发消息告诉 Nx,它是Nx的前趋节点,Nx 将它的前趋节点设置为 Nc;
step4
. Nx把它上面属于 Nc的部分数据(哈希值小于c的)迁移到Nc上;
下面举例进行分析,当P2P环境中稳定N5、N14,新加入N8后状态如下:
step1
. N8开始稳定性检测,发现N14的前驱节点是N5,进入step2
step2
. 由于N5没有介于N8和N14之间,无动作,进入step3
step3
. N8位于N14和它的前驱节点N5之间,于是N8告诉N14其前驱节点应该是N8,N14则将前驱节点指向N8,状态如下图:
step4
. N14中组件哈希值在6-8之间的记录被迁移到了N8节点上,这样N8节点就完成了一次稳定性检测。
完成N8的稳定性检测后,一段时间后会对N5节点进行稳定性检测,N5被N14告知其前驱节点是N8而不是N5自己,N5将后继节点改为N8,因为N8前驱节点为null,所以N5告知N8将其作为前驱节点,然后N8将前驱节点改为N5,经过N5的稳定性检测后,系统状态才会转变为下图的样子:
节点离开P2P网络
节点离开P2P网络分2种,我们这里主要介绍正常离开,正常离开前会做好准备工作,通知相应的节点更新其前驱和后继节点,然后将本身持有的数据迁移到后继节点上。由于节点离开,造成其他机器路由表失效,可以通过“加入新节点时的情形”介绍的方式获得更新。
异常离开一般是机器故障导致的,可以采用将同一份数据在多台机器上保留副本的方式避免。
虚拟节点
由于哈希算法使得机器映射到环状结构的位置随机,会导致负载不均衡。而且机器异质性常见,高配低配参差不齐,一致性哈希将所有机器平等对待,可能导致低配高负载的情况。
Dynamo对一致性哈希做了改造,引入虚拟节点的概念,将一个物理节点虚拟成若干的虚拟节点,分别映射到一致性哈希的环状结构不同位置,一方面尽可能的负载均衡,另外方面也兼顾了机器的异质性问题。
4. 范围分片
范围分片先将所有记录的主键进行排序,将主键空间里将记录划分成数据分片,每个数据分片存储主键控件片段内记录的所有数据。在具体存储系统时,保持一个数据分片的映射表,记录每一项记载数据分片的最小主键及对应的物理机地址。
在对记录增删改查时,查找映射表就能找到数据分片所在的物理机,数据分片在物理机的管理方式一般采用LSM数,一种高效写入的数据索引结构。