前言
所谓分布式系统顾名思义就是利用多台计算机协同解决单台计算机所不能解决的计算、存储等问题。
首先要解决的就是如何将问题拆解为可以使用多机分布式解决,使得
分布式系统中的每台机器负责原问题的一个子集。
哈希方式
哈希方式是最常见的数据分布方式,其方法是按照数据的某一特征计算哈希值,并将哈希值与机器中的机器建立映射关系,从而将不同哈希值的数据分布到不同的机器上。所谓数据特征可以是key-value 系统中的 key,也可以是其他与应用业务逻辑相关的值。
例如,一种常见的哈希方式是按数据属于的用户 id 计算哈希值,集群中的服务器按 0 到机器数减 1 编号,哈希值除以服务器的个数,
结果的余数作为处理该数据的服务器编号。
id%length或者id&(length-1)后置需要保证length是2的幂次方
哈希分布的缺点
一:可扩展性不高
一旦集群规模需要扩展,则几乎所有的数据需要被迁移并重新分布。工程中,扩展哈希分布数据的系统时,往往使得集群规模成倍扩展,按照数据重新计算哈希,这样原本一台机器上的数据只需迁移一半到另一台对应的机器上即可完成扩展。
二.容易出现数据倾斜
例如,某系统中以用户 id 做哈希分数据,当某个用户 id 的数据量异常庞大时,该用户的数据始终由某一台服务器处理,假如该用户的数据量超过了单台服务器处理能力的上限,则该用户的数据不能被处理。更为严重的是,无论如何扩展集群规模,该用户的数据始终只能由某一台服务器处理,都无法解决这个问题。
针对一的优化方案
不再简单的将哈希值与机器做除法取模映射,而是将对应关系作为元数据由专门的元数据服务器管理。访问数据时,首先计算哈希值并查询元数据服务器,获得该哈希值对应的机器。
同时,哈希值取模个数往往大于机器个数,这样同一台机器上需要负责多个哈希取模的余数。在集群扩容时,将部分余数分配到新加入的机器并迁移对应的数据到新机器上,从而使得扩容不再依赖于机器数量的成本增长。
针对二的方案
只能重新选择需要哈希的数据特征,例如选择用户 id 与另一个数据维度的组合作为哈希函数的输入,如这样做,则需要完全重新分布数据,在工程实践中可操作性不高。另一种极端的思路是,使用数据的全部而不是某些维度的特征计算哈希,这样数据将被完全打散在集群中。然而实践中有时并不这样做,这是因为这样做使得每个数据之间的关联性完全消失。
按数据范围分布
按数据范围分布是另一个常见的数据分布式,将数据按特征值的值域范围划分为不同的区间,使得集群中每台(组)服务器处理不同区间的数据。
如:已知某系统中用户 id 的值域范围是[1,100),集群有 3 台服务器,使用按数据范围划分数据的数据分布方式。将用户 id 的值域分为三个区间[1, 33),, [33, 90), [90, 100)分别由 3 台服务器负责处理。
优点
可以灵活的根据数据量的具体情况拆分原有数据区间,拆分后的数据区间可以迁移到其他机器,一旦需要集群完成负载均衡时,与哈希方式相比非常灵活。
另外,当集群需要扩容时,可以随意添加机器,而不限为倍增的方式,只需将原机器上的部分数据分区迁移到新加入的机器上就可以完成集群扩容。
缺点
按数据范围分布数据
需要记录所有的数据分布情况。一般的,往往需要使用专门的服务器在内存中维护数据分布信息,称这种数据的分布信息为一种元信息。甚至对于大规模的集群,由于元信息的规模非常庞大,单台计算机无法独立维护,需要使用多台机器作为元信息服务器.
按数据量分布
数据量分布数据与具体的数据特征无关,而是将数据视为一个顺序增长的文件,并将这个文件按照某一较为固定的大小划分为若干数据块(chunk),不同的数据块分布到不同的服务器上。与按数据范围分布数据的方式类似的是,按数据量分布数据也需要记录数据块的具体分布情况,并将该分布信息作为元数据使用元数据服务器管理。
优点
由于与具体的数据内容无关,按数据量分布数据的方式一般没有数据倾斜的问题,数据总是被均匀切分并分布到集群中。当集群需要重新负载均衡时,只需通过迁移数据块即可完成。集群扩容也没有太大的限制,只需将部分数据库迁移到新加入的机器上即可以完成扩容。
缺点
同样需要管理元信息
一致性哈希
一致性哈希的基本方式是使用一个哈希函数计算数据或数据特征的哈希值,令该哈希函数的输出值域为一个封闭的环,即哈希函数输出的最大值是最小值的前序。将节点随机分布到这个环上,每个节点负责处理从自己开始顺时针至下一个节点的全部哈希值域上的数据。
例如:某一致性哈希函数的值域为[0, 10),系统有三个节点 A、 B、 C,这三个节点处于的一致性哈希的位置分别为 1, 4, 9,则节点 A 负责的值域范围为[1, 4),节点 B 负责的范围为[4, 9),节点 C 负责的范围为[9, 10)和[0, 1)。若某数据的哈希值为 3,则该数据应由节点 A 负责处理。
优点
哈希分布数据的方式在集群扩容时非常复杂,往往需要倍增节点个数,与此相比,一致性哈希的优点在于可以任意动态添加、删除节点,每次添加、删除一个节点仅影响一致性哈希环上相邻的节点.
使用一致性哈希的方式需要将节点在一致性哈希环上的位置作为元信息加以管理,这点比直接使用哈希分布数据的方式要复杂。然而,节点的位置信息只于集群中的机器规模相关,其元信息的量通常比按数据范围分布数据和按数据量分布数据的元信息量要小很多。
缺点
随机分布节点的方式使得很难均匀的分布哈希值域,尤其在动态增加节点后,即使原先的分布均匀也很难保证继续均匀,由此带来的另一个较为严重的缺点是,当一个节点异常时,该节点的压力全部转移到相邻的一个节点,当加入一个新节点时只能为一个相邻节点分摊压力.
解决方案
引入虚节点(virtual node)的概念,系统初始时就创建许多虚节点,虚节点的个数一般远大于未来集群中机器的个数,将虚节点均匀分布到一致性哈希值域环上,其功能与基本一致性哈希算法中的节点相同。为每个节点分配若干虚节点。操作数据时,首先通过数据的哈希值在环上找到对应的虚节点,进而查找元数据找到对应的真实节点。使用虚节点改进有多个优点。首先,一旦某个节点不可用,该节点将使得多个虚节点不可用,从而使得多个相邻的真实节点负载失效节点的压里。同理,一旦加入一个新节点,可以分配多个虚节点,从而使得新节点可以负载多个原有节点的压力,从全局看,较容易实现扩容时的负载均衡。