您的位置:首页 > 数据库 > Memcache

Memcached 小探

2016-06-17 16:33 483 查看



Why use Memcached ?

随着互联网发展, 日益增长的互联网用户已经业务扩展需求, 传统关系数据库 (如Mysql) 开始出现瓶颈:

1) 对数据库高并发读写。

2)海量数据的处理。

对于Mysql来说, 作为一个关系型数据库本来就是一个庞然大物, 其处理过程非常复杂和耗时, 如sql解释, 事务处理等。当单张表出现数据量大于千万的时候, 无论如何都很难再通过自身的性能(如建立索引)去优化数据查询。 使用Nosql缓存(如本文提到的Memcached,当然还有Redis等)能够很好的解决这个问题。大多数Web应用的瓶颈在数据库访问 


Features of Memcached 

Memcached有如下特点:

1) 基于libevent 的事件处理 (所以在安装前要确保libevent依赖库已经安装)

2) 追求速度和高性能, 储存数据与内存中。所以需要注意储存的对象非永久, 服务停止后, 数据丢失。
3) 支持分布式, 但服务器端互相不通信, 需要依赖客户端算法实现。


Memcached : Distributed

上文已经提到, Memcached服务器支持分布式, 但是其分布式的算法是有客户端实现的。已 PHP 的 memcached 客户端为例,它内置的分布式算法有两种, 一种是简单通俗的取模运算或者说余数分步法,Hash(Key) % m ,m 为已经有的Memcached服务器数量,这也是默认采用的一种算法。 但去取模算法有一个明显的弊端就是,在增删节点的时候, 会导致数据重新分布,命中率会严重下降。

除了取模运算, 另外一种算法叫做一致性哈希算法 (Consistent Hashing)。它原理是将一个32位整数想象成一个已0作为环头,2的32次方-1为环尾的一个圆环。首先将服务器节点通过Hash以后投射到环中

$server1 = myHash("192.168.3.135");
$server2 = myHash("192.168.3.136");


然后再讲需要存取的Key用同样的Hash算法投射到环中。

$key1= myHash("aaa");
$key2 = myHash("bbb");


这样我们把数据的key和服务器都映射到同一个环上(一个想象的圆环)。沿着圆环顺时针方向的key出发,直到遇到同一个服务器为止,然后把数据保存到该服务器节点上。一致性哈希算法可以有效的避免在增删减点时的数据重新分布,保证了命中率。

在php memcached客户端开启的方法如下:

<?php
// use the php memcahceD client

$mc= new Memcached();

/**
* 默认为Memcached::DISTRIBUTION_MODULA  (余数分布算法)
*/
$mc -> setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);

/*
* 开启或关闭兼容的libketama类行为。当开启此选项后,元素key的hash算法将会被设置
* 为md5并且分布算法将会 采用带有权重的一致性hash分布。
* 这一点非常有用因为其他基于libketama的客户端(比如python,urby)在同样 的服务
* 端配置下可以透明的访问key。
*
*/
$mc -> setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

$mc->addServer("192.168.3.135", 11211);
$mc->addServer("192.168.3.136", 11211);

?>


谈到这里, 可能有人会问究竟如何将Key (大部分时间是String 形式存在)或者服务器节点跟32位整型数据 (上面想象的圆环)联系起来? 这就是上面代码块中我们用到的myHash算法函数,在一致性哈希分布式算法中我们通常用的哈希算法是DJBX33A算法。

DJBX33A算法,也就是time33算法(学院里有专门条目介绍了),是APR默认哈希算法,php, apache, perl, bsddb也都使用time33哈希。对于33这个数,DJB注释中是说,1到256之间的所有奇数,都能达到一个可接受的哈希分布,平均分布大概是86%。而其中33,17,31,63,127,129这几个数在面对大量的哈希运算时有一个更大的优势,就是这些数字能将乘法用位运算配合加减法替换,这样运算速度会更高。gcc编译器开启优化后会自动将乘法转换为位运算。


分享下我用PHP实现的time33算法

<?php
/**
* 模拟 PHP time33 哈希算法 实现平均哈希分布
*
* hash(i) = hash(i-1) * 33 + str[i]
*
*
* @param unknown $key
*/
function myhash($key)
{
$hash = 0;
$s    = md5($key);
$seed = 5;
$len  = 32;
for ($i = 0; $i < $len; $i++) {
// (hash << 5) + hash 相当于 hash * 33
//$hash = sprintf("%u", $hash * 33) + ord($s{$i});
//$hash = ($hash * 33 + ord($s{$i})) & 0x7FFFFFFF;
$hash = ($hash << $seed) + $hash + ord($s{$i});
}
//防止数据溢出
return $hash & 0x7FFFFFFF;
}

?>



Some Highlights

Memcached有如下注意点:

1) 存储key的长度有限制,php和C的最大长度都是250.

2) 最大存储
Value 的大小限制为1M,这由slab页大小1M限制 (修改源码可以打破这个限制)

3)
在服务器集群中,要实现memcached之间的数据拷贝需要借助第三方插件来支持(i.e. Magent)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息