当我们网站的数据很多、读写数据库频繁的时候我们就会考虑优化网站访问速度,为其添加缓存,提高用户体验,减轻数据库的压力。而Memcached就是一个不错的缓存技术系统(KV数据库)。

虽然memcached可以应对任意多个连接,使用非阻塞的网络I/O,在访问速度上是没话说,但是有时候一台Memcached服务器并不能满足我们的要求,其中一个很重要的问题是,由于Memcached是吧数据储存在内存中的(和Redis一样,但Redis支持持久化,而Memcached则没有),如果服务器崩溃了,那么数据就没了,这无疑是一个灾难。当然一般Memcached不会存储独一无二的数据,而是作为数据库的一个缓存来用,也就是说数据库里肯定是有数据备份的,但是若是数据很大呢,这么多数据需要重新从数据库里取所需要的时间也是不可小觑的。

所以有些时候我们会使用多台Memcached,分开存储数据,就算一台宕机了,也是不会对web应用产生较大的影响。

那么,切入正题。关于Memcached服务器分布式部署策略有两种:简单的一般hash分布(余数式hash)和一致性hash分布。

余数式hash算法分布部署Memcached服务器

简单来说,就是通过对输入结果进行一些hash运算加密(md5等),然后取其中一个随机字母进行ASC转换成数字,在经过一些运算(这些都是由开发者自行设计算法),生成一个32位的数字。比如现在有三台Memcached服务器,有一个数据要存,就把它的key用以上设计的算法方法运算后的数字除以3,然后得到余数再选择存入哪个Memcached。
这样的算法简单易于实现,但是存在一个问题,就是算法设计比较麻烦,不好的算法很容易导致数据存储不平衡,有的服务器存的多,有的存的少。而且不能动态添加或删除服务器的话,会影响到所有数据。

一致性hash算法分布部署Memcached服务器

一致性hash算法分布式部署策略应该具备

  • 平衡性:使数据尽可能的分布到所有缓冲区中去,使所有缓冲区都得到利用。
  • 单调性:同样的数据标识(比如key),存储(映射到)的缓冲区应该每次都一样,并且有新的缓存区加入也不会受到影响。
  • 平滑性:缓存服务器数目的平滑改变和存储的数据的平滑改变保持一致。
    (*分散性和负载由于缺乏实验,我也是似懂非懂的样子,就不滥竽充数的说了)

设计一致性hash分布式Memcached部署方案步骤

第一步:首先用设计的hash算法求出Memcached服务器(节点,一般是用服务器的ip或者主机名)的哈希值(根据字符串生成32位二进制的算法,结果有2^32种),并将其分配到0~2^32-1的圆上(把结构比作一个圆,其实是一个循环队列的数据结构,实现的时候可以用数组来实现)。

第二步:采用相同的算法求出存储数据key的哈希值,并且映射到同一个圆上。

第三步:设计的存储方法应该是从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过2^32仍然找不到服务器,就会保存到第一台memcached服务器上。

一致性hash明显的好处是动态的改变memcached服务器属性,影响的只有改变的这台服务器节点到它逆时针方向的第一个服务器节点之间的数据。只要服务器名字或者ip不变。

值得注意的问题

数据的重定向:当增加新的节点或者一台服务器不小心宕机了。就需要计算到新增或者是宕机的这个服务器和它上一个服务器节点的hash,然后对这之间的数据,进行相关的更新操作。一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。

具体做法可以在服务器ip或主机名的后面增加编号来实现。l比如上面示例,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,于是形成六个虚拟节点 。

设置虚拟节点的好处还有就是不会产生连环爆炸事件,由于在前面提到所写的程序会在一台机器宕机后,能够在之后的时间里把丢失的数据在逐一慢慢存入下一台相邻的节点服务器,有时候可能是因为数据量过大导致服务器崩溃的,这样的话可能导致服务器一台台的被装满然后崩溃。虚拟节点也一定程度上避免了连环爆炸的发生。

补充:适合memcached的场景

  • 如果网站包含了访问量很大的动态网页,因而数据库的负载将会很高。由于大部分数据库请求都是读操作,那么memcached可以显著地减小数据库负载。
  • 如果数据库服务器的负载比较低但CPU使用率很高,这时可以缓存计算好的结果( computed objects )和渲染后的网页模板。
  • 利用memcached可以缓存session数据、临时数据以减少对他们的数据库写操作。
  • 缓存一些很小但是被频繁访问的文件。
  • 缓存Web 变动不是很频繁业务或RSS feeds(共享内容)的结果。