1、下载并安装Memcache服务器端
官网,libevent:http://www.monkey.org/~provos/libevent/,Memcache:http://memcached.org/
//1.先安装libevent。这个东西在配置时需要指定一个安装路径,即./configure –prefix=/usr
//2.再安装memcached,只是需要在配置时需要指定libevent的安装路径即./configure –with-libevent=/usr
cd /usr/local/src
wget https://sourceforge.net/projects/levent/files/libevent/libevent-2.0/libevent-2.0.22-stable.tar.gz
wget http://www.memcached.org/files/memcached-1.4.24.tar.gz
wget https://pecl.php.net/get/memcached-2.2.0.tgz
wget https://launchpad.net/libmemcached/1.0/1.0.18/+download/libmemcached-1.0.18.tar.gz
tar zxf libmemcached-1.0.18.tar.gz
cd libmemcached-1.0.18
./configure --prefix=/usr/local/libmemcached --with-memcached
make && make install
tar zxf libevent-2.0.22-stable.tar.gz
cd libevent-2.0.22-stable
./configure --prefix=/usr
make && make install
cd /usr/local/src
tar zxf memcached-1.4.24.tar.gz
cd memcached-1.4.24
./configure --with-libevent=/usr
make && make install
/usr/local/bin/memcached -d -m 10 -u root -l 192.168.1.30 -p 12000 -c 256 -P /tmp/memcached.pid
cd /usr/local/src
tar zxf memcached-2.2.0.tgz
cd memcached-2.2.0
phpize
./configure --enable-memcached --with-php-config=php-config --with-libmemcached-dir=/usr/local/libmemcached --disable-memcached-sasl
make && make install
echo 'extension=memcached.so' > /etc/php.d/memcached.ini
service php-fpm reload
参数解释
-d选项是启动一个守护进程
-m是分配给Memcache使用的内存数量,单位是MB,我这里是10MB
-u是运行Memcache的用户,我这里是root
-l是监听的服务器IP地址,如果有多个地址的话,我这里指定了服务器的IP地址192.168.1.30
-p是设置Memcache监听的端口,我这里设置了12000,最好是1024以上的端口
-c选项是最大运行的并发连接数,默认是1024,我这里设置了256,按照你服务器的负载量来设定
-P是设置保存Memcache的pid文件,我这里是保存在 /tmp/memcached.pid
防火墙
# iptables -A INPUT -p tcp -s 192.168.1.30 –dport 12000 -j ACCEPT
# iptables -A INPUT -p udp -s 192.168.1.30 –dport 12000 -j ACCEPT
想开机自动启动的话,只需在/etc/rc.d/rc.local中加入一行命令就可以了
2、测试
<?php
$m = new Memcached();
/* Add 2 servers, so that the second one
is twice as likely to be selected. */
$m->addServer('192.168.1.30', 12000, 33);
$v=str_repeat('a',1024*1024);
if( $m->add('mystr',$v,3600)){
echo '原始数据缓存成功!';
}else{
echo '数据已存在:'.$m->get("mystr");
}
memcached set数据的时候是默认压缩的,可以通过setOption(memcahed::OPT_COMPRESSION,0)来设置,也就是说memcached server不能存储超过1M的数据,但是经过客户端压缩数据后,只要小于1M的数据都能存储成功
3、memcached的操作
Memcached — Memcached类
Memcached::add — 向一个新的key下面增加一个元素
Memcached::addByKey — 在指定服务器上的一个新的key下增加一个元素
Memcached::addServer — 向服务器池中增加一个服务器
Memcached::addServers — 向服务器池中增加多台服务器
Memcached::append — 向已存在元素后追加数据
Memcached::appendByKey — 向指定服务器上已存在元素后追加数据
Memcached::cas — 比较并交换值
Memcached::casByKey — 在指定服务器上比较并交换值
Memcached::__construct — 创建一个Memcached实例
Memcached::decrement — 减小数值元素的值
Memcached::decrementByKey — Decrement numeric item's value, stored on a specific server
Memcached::delete — 删除一个元素
Memcached::deleteByKey — 从指定的服务器删除一个元素
Memcached::deleteMulti — Delete multiple items
Memcached::deleteMultiByKey — Delete multiple items from a specific server
Memcached::fetch — 抓取下一个结果
Memcached::fetchAll — 抓取所有剩余的结果
Memcached::flush — 作废缓存中的所有元素
Memcached::get — 检索一个元素
Memcached::getAllKeys — Gets the keys stored on all the servers
Memcached::getByKey — 从特定的服务器检索元素
Memcached::getDelayed — 请求多个元素
Memcached::getDelayedByKey — 从指定的服务器上请求多个元素
Memcached::getMulti — 检索多个元素
Memcached::getMultiByKey — 从特定服务器检索多个元素
Memcached::getOption — 获取Memcached的选项值
Memcached::getResultCode — 返回最后一次操作的结果代码
Memcached::getResultMessage — 返回最后一次操作的结果描述消息
Memcached::getServerByKey — 获取一个key所映射的服务器信息
Memcached::getServerList — 获取服务器池中的服务器列表
Memcached::getStats — 获取服务器池的统计信息
Memcached::getVersion — 获取服务器池中所有服务器的版本信息
Memcached::increment — 增加数值元素的值
Memcached::incrementByKey — Increment numeric item's value, stored on a specific server
Memcached::isPersistent — Check if a persitent connection to memcache is being used
Memcached::isPristine — Check if the instance was recently created
Memcached::prepend — 向一个已存在的元素前面追加数据
Memcached::prependByKey — Prepend data to an existing item on a specific server
Memcached::quit — 关闭所有打开的链接。
Memcached::replace — 替换已存在key下的元素
Memcached::replaceByKey — Replace the item under an existing key on a specific server
Memcached::resetServerList — Clears all servers from the server list
Memcached::set — 存储一个元素
Memcached::setByKey — Store an item on a specific server
Memcached::setMulti — 存储多个元素
Memcached::setMultiByKey — Store multiple items on a specific server
Memcached::setOption — 设置一个memcached选项
Memcached::setOptions — Set Memcached options
Memcached::setSaslAuthData — Set the credentials to use for authentication
Memcached::touch — Set a new expiration on an item
Memcached::touchByKey — Set a new expiration on an item on a specific server
参见:http://php.net/manual/zh/book.memcached.php
注意事项:key的长度不能大于250字符,缓存对象的大小不能大于1MB,item对象的过期时间最长可以达到30天
如果使用的Memcached客户端支持"key的前缀"或类似特性,那么key(前缀+原始key)的最大长度是可以超过250个字符的。
推荐使用较短的key,这样可以节省内存和带宽。
4、适用的场景
1)如果网站包含了访问量很大的动态网页,因而数据库的负载将会很高。由于大部分数据库请求都是读操作,那么memcached可以显著地减小数据库负载
2)如果数据库服务器的负载比较低但CPU使用率很高,这时可以缓存计算好的结果( computed objects )和渲染后的网页模板(enderred templates)
3)利用memcached可以缓存session数据、临时数据以减少对他们的数据库写操作
4)缓存一些很小但是被频繁访问的文件
5)缓存Web 'services'(非IBM宣扬的Web Services,译者注)或RSS feeds的结果
5、memcached的原理
1)Big-O
memcache的大部分功能(add,get,set,flush等)都是O(1)的操作,这意味着它们是恒定的时间功能,无论缓存里存了多少东西,这功能将只需要获得缓存中的一项,所以你不能遍历所有项目里的item
2)LRU算法
LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的,它将删除最长时间不使用的数据。该数据可能并不是最大的数据,也不是第一个存储在缓存中的数据。
在实现时,一般使用一个哈希表类存储被缓存的对象,和一个双向链表类存储对象被使用的情况
所有的对象有有一个counter,这个counter记录了一个时间戳。当一个新的对象被创建的时候,counter就会被设置成当前时间。当一个对象被读取的时候,就会重置counter为当前的时间。一旦memcache需要为一个新的对象腾出空间而剔除旧对象时,只需要找到最低的counter对应的那个对象,这个对象要么是一直没有被读取或者是很长时间之前被读取(说明这个对象不需要了,否这的话该对象的counter应该会很接近当前时间)。
这样创建了一个简单系统,并使用了非常高效的缓存。如果它不被使用,就会被踢出系统。
3)slab allocation
Memcached的内存分配以Page为单位,Page默认值为1M,可以在启动时通过-I参数来指定。
Slab Allocation的原理——将分配的内存分割成各种尺寸的块(chunk), 并把尺寸相同的块分成组(chunk的集合),每个chunk集合被称为slab
Slab是由多个Page组成的,Page按照指定大小切割成多个chunk
Growth Factor
memcached在启动时通过-f选项可以指定 Growth Factor因子。该值控制slab之间的差异,chunk大小的差异。默认值为1.25。
通过memcached-tool查看指定memcached实例的不同slab状态,可以看到各Item所占大小(chunk大小)差距为1.25
[root@localhost src]# memcached -u root -vv
slab class 1: chunk size 80 perslab 13107
slab class 2: chunk size 104 perslab 10082
slab class 3: chunk size 136 perslab 7710
slab class 4: chunk size 176 perslab 5957
slab class 5: chunk size 224 perslab 4681
slab class 6: chunk size 280 perslab 3744
slab class 7: chunk size 352 perslab 2978
slab class 8: chunk size 440 perslab 2383
slab class 9: chunk size 552 perslab 1899
slab class 10: chunk size 696 perslab 1506
slab class 11: chunk size 872 perslab 1202
slab class 12: chunk size 1096 perslab 956
slab class 13: chunk size 1376 perslab 762
slab class 14: chunk size 1720 perslab 609
slab class 15: chunk size 2152 perslab 487
slab class 16: chunk size 2696 perslab 388
slab class 17: chunk size 3376 perslab 310
slab class 18: chunk size 4224 perslab 248
slab class 19: chunk size 5280 perslab 198
slab class 20: chunk size 6600 perslab 158
slab class 21: chunk size 8256 perslab 127
slab class 22: chunk size 10320 perslab 101
slab class 23: chunk size 12904 perslab 81
slab class 24: chunk size 16136 perslab 64
slab class 25: chunk size 20176 perslab 51
slab class 26: chunk size 25224 perslab 41
slab class 27: chunk size 31536 perslab 33
slab class 28: chunk size 39424 perslab 26
slab class 29: chunk size 49280 perslab 21
slab class 30: chunk size 61600 perslab 17
slab class 31: chunk size 77000 perslab 13
slab class 32: chunk size 96256 perslab 10
slab class 33: chunk size 120320 perslab 8
slab class 34: chunk size 150400 perslab 6
slab class 35: chunk size 188000 perslab 5
slab class 36: chunk size 235000 perslab 4
slab class 37: chunk size 293752 perslab 3
slab class 38: chunk size 367192 perslab 2
slab class 39: chunk size 458992 perslab 2
slab class 40: chunk size 573744 perslab 1
slab class 41: chunk size 717184 perslab 1
slab class 42: chunk size 1048576 perslab 1
<26 server listening (auto-negotiate)
<27 server listening (auto-negotiate)
<28 send buffer was 112640, now 268435456
<32 send buffer was 112640, now 268435456
<28 server listening (udp)
<31 server listening (udp)
<32 server listening (udp)
<35 server listening (udp)
<30 server listening (udp)
<29 server listening (udp)
<34 server listening (udp)
<33 server listening (udp)
Slab Allocation的缺点
Slab Allocation可以有效的解决内存碎片问题,但是在如下情况下,会导致内存的浪费:
每个slab的chunk大小是固定的,当item的占用空间实际小于chunk大小时,会出现内存浪费
每个slab的大小是固定的(因为page是固定的),当slab不能被他所拥有的chunk整除时,会出现内存浪费
按照Growth Factor因子生成指定大小的slab,而某slab id根本未被使用时,会出现内存浪费
4)分布式、一致性hash算法