• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

Memcached分布式机制

Memcached 彭东稳 8年前 (2016-01-21) 22065次浏览 已收录 0个评论

Memcached的分布式

Memcached虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能。服务器端仅包括内存存储功能,至于memcached的分布式,则是完全由客户端程序库实现的。这种分布式是memcached的最大特点。

那么memcached的分布式是什么意思呢?

下面假设memcached服务器有node1node2node3三台,应用程序要保存键名为“tokyo”、“kanagawa”、“chiba”、“saitama”、“gunma”的数据。

首先向memcached中添加“tokyo”,将“tokyo”传给客户端程序库后,客户端实现的算法就会根据“键”来决定保存数据的memcached服务器。服务器选定后,即命令它保存“tokyo”及其值。如下图:

Memcached分布式机制

同样,“kanagawa”、“chiba”、“saitama”、“gunma”都是先选择服务器再保存。接下来获取保存的数据。获取时也要将要获取的键“tokyo”传递给函数库。函数库通过与数据保存时相同的算法,根据“键”选择服务器。使用的算法相同,就能选中与保存时相同的服务器,然后发送get命令。只要数据没有因为某些原因被删除,就能获得保存的值。

Memcached分布式机制

这样,将不同的键保存到不同的服务器上,就实现了memcached 的分布式。memcached 服务器增多后,键就会分散,即使一台 memcached 服务器发生故障无法连接,也不会影响其他的缓存,系统依然能继续运行。

分布式算法

1Memcached分布式部署之普通Hash算法分布

普通Hash算法是根据余数计算分散根据服务器台数的余数进行分散,求得Key的整数哈希值,再除以服务器台数,根据其余数来选择服务器。下面提供一个图供参考。

Memcached分布式机制

比如:对于字符串string(一个Key),先求得string的整数哈希值,这里比如是50。而服务器的数目是3,50对3取余等于2,那么此string对应的节点就是node2。所以路由算法把string路由到node2服务器上存储。由于求哈希值随机性比较强,所以使用余数hash路由算法就可以保证缓存数据在整个Memcache服务器集群中有比较好的均匀性分布。

余数计算的方法简单,数据的分散性也相当优秀,普通Hash分布对于Memcached服务器数量固定的情况推荐使用。但也有其缺点,那就是当添加或移除服务器时,缓存重组的代价相当巨大。添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而影响缓存的命中率。对于服务器集群伸缩性支持的不太很好。

比如:由于3台memcache集群无法支持现有的业务,需要在添加2台成员,此时服务器集群由3台变成了5台。那么你就需要在客户端添加服务器列表,此时对于key(string)哈希值还是50,路由计算时就是50除以5取余等于0,对应的服务器是node0,这就会导致客户端再次查询string时缓存不会命中,同时对于node2来说也是浪费了内存。

由于hash算法主要依据服务器数来进行分布,所以当服务器数有变化时就会导致整个集群数据访问出现问题。这里只是列举了一个Key,在实际业务中对于增加服务器或减少服务器会导致大量的Key缓存不会命中。这显然也是无法接受的,所有对于此类分布式又出来了另外一种算法,就是一致性Hash算法。

2Memcached分布式部署之一致性Hash算法分布(Consistent Hashing

Memcache服务器数量固定时,普通Hash分布可以很好的运作。但是当服务器数量发生改变时,问题就出来了。因为同一个KeyHash算法处理后,与服务器数量取模,会导致结果与服务器数量未变化时不同,这就导致之前保存的数据丢失。采取一致性Hash分布可以有效的解决这个问题,把丢失的数据减到最小(注意这里并没有说完全不丢失)。

一致性Hash分布算法分4个步骤:

步骤1:将一个32位整数[0 ~ (2^32-1)]想象成一个环型Hash空间,其中0 作为开头,(2^32-1) 作为结尾。

步骤2:通过Hash函数把Key处理成整数。这样就可以在环上找到一个位置与之对应。

步骤3:把Memcached服务器群映射到环上,使用Hash函数处理服务器对应的IP地址即可。

步骤4:把数据映射到Memcached服务器上。查找一个Key对应的Memcached服务器位置的方法如下:从当前Key的位置,沿着圆环顺时针方向出发,查找位置离得最近的一台Memcached服务器,并将Key对应的数据保存在此服务器上。

大概过程就是如下图:

Memcached分布式机制

将string交给hash函数处理,换成整数比如为50,可以在环上找到一个对应的位置。然后处理服务器的IP也换算成整数,这里比如有node0为30、node1为80、node2为120,那么根据数据映射到Memcached服务器上的规则,从当前key的位置,沿着圆环顺时针方出发,查找位置离得最近的一台Memcached服务器进行数据存储,那么离50顺时针方向最近的数为80,所以就存储在node1这台服务器上。也很好理解。

上面对一致性hash算法说完之后,发现跟hash算法做的事情是一样的,并没有什么改变啊?的确没有什么变化,都是存储数据。但是当集群发生增加或较少服务器数量时呢?就能体现出一致性hash算法的有点了。比如对于现有的3台集群在添加1台node3服务器时会跟hash算法发生什么区别呢?

这里比如node3经过hash函数处理之后值为65,那么查找string Key时,由于string的哈希值为50,所以客户端路由会去离50顺时针方向最近的一台主机上获取缓存值,此时由于添加了一台hash值为65的node3服务器。那么客户端就会去node3服务器上查找string,当然也就发生了缓存命中失败,客户端又需要重新去数据库查找数据了。同样是缓存命中失败,但是一致性Hash算法只会影响到新添加服务器顺时针最近的一台主机,那就是hash值为80的服务器,而影响的Key的范围最大也就是从圆环位置为30到80这50个Key(最大哦),并不会像Hash算法那么使整个集群发生动荡。这就是一致性hash算法,也挺简单。

最后说一下,对于在个圆环上一致性Hash算法是怎么去找到顺时针方向离它最近的一个节点呢?这个就是使用了算法中的二叉树算法,二叉树算法很简单博客中搜索二叉树算法有介绍,一看就明白。至于一致性Hash算法想具体了解的,可以好好看看“Memcached分布式一致性hash算法”。

Memcache使用一致性Hash算法实例(在同一台MC服务器上测试):

先在Memcached服务器上开启三个实例

然后在网站目录下建立一个hash.php的页面,代码如下:

然后在浏览器中执行http://192.168.60.10/hash.php,执行完之后会在三台服务器上一共存储100个键值,接下来分别在三台MC服务器上进行查看各自存储的键值。

第一台:11211

第二台:11212

第三台:11213

可以看到三台MC服务器上一共存储刚好100个键值。


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (0)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!