当前memcached,redis这类分布式kv缓存已经很是广泛。咱们知道memcached的分布式实际上是一种"伪分布式",也就是它的服务器节点之间实际上是无关联的,之间没有网络拓扑关系,由客户端来决定一个key要存放在哪台机器。redis
具体来说,假设咱们有多台memcached服务器,编号分别为m0, m1, m2.. 对于一个key,由客户端来决定存放到哪台机器,最简单的办法就是key % N, 其中N是机器的总数缓存
可是有一个问题,一旦机器数增长或减小,N发生变化,key去mod新旧N获得的机器编号大几率不相等,那么以前存放的数据就所有无效了。服务器
基于上面的问题,提出了hash环的概念。hash环的过程有两次hash网络
(1) 把全部的机器编号hash到这个环上分布式
(2) 把key也hash到这个环上,而后在这个环上进行匹配,看这个key和哪台机器匹配memcached
具体过程是这样: 假定有一个hash函数,其值空间为(0 ~ 2^32-1)。也就是说,其hash值是个32位无整型数字,这些数字组成一个环。首先对机器进行hash(好比根据机器ip),算出每台机器在这个环上的位置; z再对key进行hash,算出该key在环上的位置,而后从这个位置往前走,遇到的第一台机器就是该key对应的机器,就把该(key, value)存储到该机器上,以下图所示。函数
首先计算出每台cache服务器在环上的位置(图中浅蓝色的大圆圈),而后每来一个key计算出value填到环上的位置(图中橙色的小圆圈),而后顺时针走,遇到的第一个机器,就是要存储的机器spa
这里的关键点是:当机器数N变化时,其余机器在环上的位置并不会发生改变。这样只有增长/减小的那台机器附近的数据会失效,其余机器上的数据仍是有效的。blog
当机器不不少时,极可能出现几台机器在环上面贴的很近,分布很不均匀。这将会致使大部门数据集中在某几台机器上。ip
为了解决这个问题,能够引入"虚拟机器"的概念,也就是说,一台机器须要在环上映射出多个位置。好比咱们用机器的ip来hash,那么咱们能够在ip后面加几个编号,形如ip_1, ip_2, ip_3... 这样就实现了一台物理机器映射出了多个虚拟机器的编号。
数据首先映射到"虚拟机器"上,再从"虚拟机器"映射到物理机器上。由于虚拟机器能够不少,在环上均匀分布,从而保证数据相对均匀地分布在物理机器上。
上面咱们提到了服务器的机器数N的变化,那么如何通知到客户端呢
一种笨方法就是手动,当机器数N变化,从新配置客户端,重启客户端。
另一种,引入zk,服务器的节点列表注册到zk上面,客户端监听zk。发现节点数发生变化,自动更新本身的配置。
固然不用zk用一个其余的中心节点也能够,只要能实现这种更改的通知便可(也即分布式服务协调)