背景
读大学的时候我们就从数据结构课本中就知道数组和链表的区别和优缺点。
假设有如下数据:
数组A=[1,2,3,4,5,6,7,8,9,10],
链表L=[1->2->4->6->8->10]。
数组A中所有的元素都遵循一个全局的规范,即根据地址(对应小标索引)顺序而形成的一个集合,由于是全局的规范那么从整体全局角度很容易找到其中每个元素(从感觉上来说就是有一种全局的知识)。
而链表L中每个元素都只关注前面是谁后面是谁(局部知识),所以没找一个元素必须从头索引起来。
带有全局知识的集合便于被外界使用但是维护成本高。比如你像4后面添加一个元素12必须把后面的元素依次往后移动(维持原来的集合规范)。
带有局部知识的集合不便于外界找到内部元素但是维护成本低,比如你在4后面添加一个元素5,4->5->6那么只需要修改4,5的箭头指向即可。
更形象的说,数组更像这样一个场景:老师依照次序给学生安排座位,这种场景下老师对每个学生坐在哪里了如指掌。链表更像是每个学生自发的,每个人只坐在自己喜欢的人后面。
一致性hash中的整体和局部视角
在分布式系统中,数据经过路由存储到其中的一个节点。那么怎么路由呢?最简单的办法是求余,求余路由规则为:(data%nodecount)余数为0的数据放在编号为node0节点(依次,余数为1的数据放在编号为node1的节点,余数为2放在编号为node2节点)。
假设我们有如下数据 1 3 6 9 10 12 14 15,3台服务器node0,node1,node2。
根据(data% count(node))规则,数据分布如下:node1(3 6 9 12 15), node1(1 10),node2(14)。
假设某一时刻node2宕机了,那么1 3 6 9 10 12 14 15 应该的分布如下:
node1(1 3 9 15),node2(6 10 12)。而数据14 随着node2宕机在缓冲区中消息。
此时要移动的数据为(1 6 10 12)
由于其路由规则 (data % count(node))依赖于节点数量这个全局知识所以当全局规则变动的时候 原有整个系统需要重新编排维持原有条件。
为了解决由于节点宕机导致大部分数据都需要移动的话,需要把全局规则变成局部规则。像链表一样一个节点挂了只对相邻节点有影响。依此想法可以把所有节点组成一个链表(环状的链表) A->B->C->D ,当C挂掉的时候只需要把本应该落地到C节点的数据依顺序落地到下一个节点D就行。
一致性hash的均匀性:
由于外部数据不确定性经过hash()函数后数据分布可能非常不均匀, 假设有一串数据(1 3 5 7 8 10 11 15)经过hash(data%(2)) 之后,大部分(1 3 5 7 11 15)数据 都分布在node1,只有(8 10)分布在node2上。
那么我们可以抽出一层逻辑节点,(1 3 5 7 8 10 11 15) ---> 数据与逻辑节点 对应 ---> 逻辑节点与物理节点对应。
为什么有了逻辑节点数据就会相对均匀呢?理由如下:
1.逻辑节点数量一般比物理节点多比如32 个,比如(1 3 5 7 8 10 11 15 32 33 35)%32 求余后会均匀分布在逻辑节点里。逻辑节点数量比较多分布会相对均匀和平滑。
2.下一步我们保证逻辑节点与物理节点,我们可以动态维持逻辑节点与物理节点的映射。比如新加一台机器C4,此时发现某一些区间逻辑节点相对比较少(负责区域比较多,对应压力也会比较大),我们可以单一的把该C4拆分成几个逻辑节点把这几个逻辑节点插入进去(单独一一维护逻辑节点与物理节点的映射)。 由于每个节点负责一个区间,新加入节点只会分担相邻节点的数据(而对其他节点没有影响)。
说在后面的话
这是我由局部和全局哲学反思 计算机中的设计。全局对整体更容易控制具有全局的知识,但是当变更时候要维持体系一致性需要的代价就高。
网友评论