memcache 原理
两个线程,两种算法,两种方案 两种监控(命令+工具)
memcache 用的是多路复用I/O模型,使用多线程,-t指定开启线程数,等于cpu个数就行,它只能存储不大于1MB数据,存储数据用slab算法,减少生成内存碎片。slab算法把美1MB大小内存块称为一个slab页,每次向系统申请一个slab页,然后通过分割算法把这个slab页分割成若干chunk块 P380,memcache不是过期自动删除,而是用到的时候删除,减小开销,用的是LRU算法,从尾部寻找,因为最新数据都放在头部,如果没有,就拉大时间间隔查找,还是没有就返回NULL(申请内存失败)
memcahe用多线程模型,主线程接收请求,然后将请求轮询发送给工作线程,工作线程把连接push到CQ队列中,l通知工作线程,工作线程把CQ队列上的客户端连接注册到libevent上,ibevent侦听客户端连接的读写事件操作数据
memcache分布方法:根据键值与排序后的服务器值比大小,逆向寻找和存入对应的服务器
普通hash:用hash函数把key转化成整数,然后和memcached服务器数量取模,但是增删服务器会导致取模结果不同,数据丢失
一致性hash:把服务器(server)和key都映射到hash上,然后让key顺时映射到相应的server上,添加服务器的时候,根据添加的服务器逆时寻找到和前一个服务器之间的数据并映射上,删除的时候,将下一个顺时服务器逆时寻找和前一个服务器之间的数据并映射上,
管理工具:
memcached stats stats reset stats slabs stats items set|get gets
memcached-tool
memcached.php
nagios+cacti
UDFs+memcacheQ
redis
redis 支持多个数据类型,string--静态数据,访问次数 list--消息队列,头部和尾部 set--唯一事件,投票和昵称 sorted set--优先级队列,顶贴次数 hash,支持两种数据持久化,snapshoting(快照) append-only file(追加),支持主从复制
sort patter|limit|asc desc alpha | store dstkey
客户端:redis-cli redis-server redis-benchmark
配置文件 /etc/redis.conf
事务处理,只能保证一个客户端连续执行,中间不会插入其他客户端,exec执行,discard取消,失败后不能回滚
持 久化,save和bgsave命令执行,是阻塞操作,而且是把内存数据完整写入磁盘,save 900 1 经过900秒或数据更改1次就进行内存快照,建议不适用这种方法;另外一种是日志追加(aoef),写入日志尾部,redis重启时读 appendonly.aof文件,但操作系统I/O有缓存,日志追加不见得能立即写入文件,用fsync函数强制写入,具体有,appendonly yes appendfsync always appendfsync everysec appendfsync no,但会有多余命令,比如incr 100,会有99条废命令,为了压缩日志,redis 的bgrewriteaof命令,把内存数据保存到临时文件替换原有的,也可以用其他持久化方式,比如Berkeley DB或Tokyo Cabinet
主从同步,slave连接上master,发送 fsync同步请求,master备 份db文件发给slave,这个动作是单线程的,slave清空数据库数据并读取,master把用户修改数据发给slave,主从配置用 slave of 192.168.1.1 6379,主从配置是一对多,slave不会阻塞master,master同时处理客户端请求,只在slave上进行数据持久化,
使用消息队列发微博,避免mysql的too many connections ,把消息存在redis中,然后转发给mysql和存session(session_set_save_handler),sessionid作为key,data当成value存取
//weibo list
$redis=new Redis('127.0.0.1',6379);
$redis->connect();
$weibo=new Weibo();
$redis->lpush('webo_list',json_encode($weboinfo));//插入
while(true){
if($redis->lsize('weibo_list')>0){
$info = $redis->rpop('weibo_list');//读取
$info = json_encode($info);
$weibo->post()
}
}
常用命令
http://redis.readthedocs.org/en/latest/
http://langgufu.iteye.com/blog/1434408
http://www.cnblogs.com/oubo/archive/2011/09/07/2394568.html
http://www.linuxidc.com/Linux/2012-03/57573.htm
http://blog.51yip.com/cache/1439.html
http://hi.baidu.com/aqia230/item/a8f07bdfaf028fe2b3f7777c
redis 进阶
kv位置,vm页数、配置和交换过程以及交换方式
内存淘汰、清楚数据、关闭连接的原理
redis 把value放在硬盘,key放在内存中,redis快速定位value的位置,找到磁盘上的value,redis会把很少访问且占用内存大的对象交换 到磁盘中,VM是基于页的概念,一个页上有多个object对象,redis对象类型存在于多个页上,它自己能控制换入的粒度,磁盘中压缩后的对象比内存 中小很多,所以比系统I/O次数要少
配置项P397
vm-enabled yes
vm-swap-file 存储位置
vm-max-memory 超过内存定量就刷道磁盘
vm-max-threads 0会阻塞其他用户,和CPU个数一致就行
vm-page-size redis在内存中保存一个bitmap映射这些页是否被占用,
vm-pages
持 久化方法是子进程创建rdb文件,其他客户端提交的请求由父进程提供,子进程仅把数据写入rdb,然后退出。子进程和父进程共享一个swap,因为父进程 会随时依照请求把对象换入内存,子进程也需要访问swap得到数据。后台子进程做快照时,父进程不允许把内存中对象保交换到swap文件,连个进程用只读 方式访问swap文件,问题是,子进程内存快照时,不能讲新对象换出,redis会申请更多内存,就算超过了vm-max-meory设置,由于执行速度 快一般不会出现。VM系统设计将redis中的object从内存中交换到硬盘,释放内存
交 换到磁 盘里,value对应的redis object将被替换成VM pointer来保存value的磁盘信息,它们都有一个storage字段用来标识存储位置,key在内存、value在磁盘、value在磁盘但正在 加载到内存,value在内存但正在刷写到磁盘
交换的过程是,计算占 用swap文件多少页,在 swap中找到一段连续页空间保存这个对象,把对象写入swap文件,redis会锁swap文件,防止其他线程读写,写入swap文件,object换 成vmpointer,storage字段改成已被刷写到磁盘。反过来加载到内存也一样,锁swap,把rdb写入内存
阻塞swap value object->pointer,storage chagned,释放内存 和非阻塞 I/O排队和处理,redis能同时处理其他客户端请求,只有交换出来的数据延迟
内存淘汰方法有随机淘汰法、LRU淘汰算法(最近最少使用)和TTL淘汰算法(最快过期)
对象应用计数器,get +1 del-1 get后归0
自动关闭超时连接,如果使用连接池,timeout就设为0,关闭这个功能
清除数据一个是系统每次随机获取10个清掉,还有就是用户获取(get hget)不存在就删掉.先判断是否过期,过期就删了,del还会删掉过期时间信息,因为定时器只随机删除过期数据,不可能完全删除,所以要进行过期判断。
http 缓存
http:
不缓存或加密或不存在etag或last-modifeid则不缓存
新鲜度:完整过期时间 使用过缓存副本且足够新鲜,最后更新时间在上次使用过期之前,副本直接送出,太旧发出校验请求,是否继续使用缓存
避免post,不会被缓存
是否缓存->是否新鲜->是否再验证->返回数据
expires—通用
cache- control—通用+请求 max-age s-maxage public no-cache no-store must-revalidate proxy-prevalidate last-modify第一次请求 if-modified-since第二次请求 true 304
etag--响应 响应时给出,同if-none-match验证,false 304 true200
header(‘Cache-Control:no-cache,must-revalidate’);
header(‘Pragma:no-cache’)
header(‘Cache-control:max-age=86400,must-revalidate’)
header(‘Last-Modified:’.gmdate(‘D,d M Y H:i:s’).’GMT’)
header(‘Expires:’.gmdate(‘D d M Y H:i:s’,time()+86400’).’GMT')
//Memcache
<?php
/*********************************************************************************
* InitPHP 2.0 国产PHP开发框架 Dao-memcached 内存缓存
*-------------------------------------------------------------------------------
* 版权所有: CopyRight By initphp.com
* 您可以自由使用该源码,但是在使用过程中,请保留作者信息。尊重他人劳动成果就是尊重自己
*-------------------------------------------------------------------------------
* $Author:zhuli
* $Dtime:2011-10-09
***********************************************************************************/
class memcachedInit {
private $memcache;
/**
* Memcache缓存-设置缓存
* 设置缓存key,value和缓存时间
* @param string $key KEY值
* @param string $value 值
* @param string $time 缓存时间
*/
public function set_cache($key, $value, $time = 0) {
return $this->memcache->set($key, $value, false, $time);
}
/**
* Memcache缓存-获取缓存
* 通过KEY获取缓存数据
* @param string $key KEY值
*/
public function get_cache($key) {
return $this->memcache->get($key);
}
/**
* Memcache缓存-清除一个缓存
* 从memcache中删除一条缓存
* @param string $key KEY值
*/
public function clear($key) {
return $this->memcache->delete($key);
}
/**
* Memcache缓存-清空所有缓存
* 不建议使用该功能
* @return
*/
public function clear_all() {
return $this->memcache->flush();
}
/**
* 字段自增-用于记数
* @param string $key KEY值
* @param int $step 新增的step值
*/
public function increment($key, $step = 1) {
return $this->memcache->increment($key, (int) $step);
}
/**
* 字段自减-用于记数
* @param string $key KEY值
* @param int $step 新增的step值
*/
public function decrement($key, $step = 1) {
return $this->memcache->decrement($key, (int) $step);
}
/**
* 关闭Memcache链接
*/
public function close() {
return $this->memcache->close();
}
/**
* 替换数据
* @param string $key 期望被替换的数据
* @param string $value 替换后的值
* @param int $time 时间值
* @param bool $flag 是否进行压缩
*/
public function replace($key, $value, $time = 0, $flag = false) {
return $this->memcache->replace($key, $value, false, $time);
}
/**
* 获取Memcache的版本号
*/
public function getVersion() {
return $this->memcache->getVersion();
}
/**
* 获取Memcache的状态数据
*/
public function getStats() {
return $this->memcache->getStats();
}
/**
* Memcache缓存-设置链接服务器
* 支持多MEMCACHE服务器
* 配置文件中配置Memcache缓存服务器:
* $InitPHP_conf['memcache'][0] = array('127.0.0.1', '11211');
* @param array $servers 服务器数组-array(array('127.0.0.1', '11211'))
*/
public function add_server($servers) {
$this->memcache = new Memcache;
if (!is_array($servers) || empty($servers)) exit('memcache server is null!');
foreach ($servers as $val) {
$this->memcache->addServer($val[0], $val[1]);
}
}
// public function __construct() {
// $this->_memcache = new Memcache($this->_memcached_conf);
// $this->_memcache->addserver('127.0.0.1', '11211');
// }
}
$conf = array(array('127.0.0.1','11211'));
$mem = new memcachedInit;
//var_dump($mem);
$conn = $mem->add_server($conf);
$stats = $mem->getStats();
$mem->getVersion();
$mem->set_cache('name','zy','1200');
$mem->get_cache('name');
$mem->clear('name');
$mem->get_cache('name');
$mem->set_cache('name','zy','1200');
$mem->get_cache('name');
$mem->replace('name','zhouy');
$mem->get_cache('name');
$mem->set_cache('num',1);
$mem->get_cache('num');
$mem->increment('num');
$mem->get_cache('num');
$mem->decrement('num',2);
echo $mem->get_cache('num');
/usr/local/bin/memcached -d -m 10 -u root -l 172.28.5.2 -p 12000 -c 1024 –P /tmp/memcached.pid
####相关选项说明
7个
-d 表示启动一个守护进程
-m 是分配给memcached使用的内存
-u 运行memcached的用户
-l 是memcached监听的ip
-p 是memcached监听的端口
-c memcache运行的最大并发连接数
-P 是设置memcache的pid文件
11个
add_server
$host服务器的地址
$port服务器端口
$persistent是否是一个持久连接
$weight这台服务器在所有服务器中所占的权重
$timeout连接的持续时间
$retry_interval连接重试的间隔时间,默认为15,设置为-1表示不进行重试
$status控制服务器的在线状态
$failure_callback允许设置一个回掉函数来处理错误信息。
set
get
delete
flush
flush_all
close
increment
decrement
getStats
1. pid: memcached服务进程的进程ID
2. uptime: memcached服务从启动到当前所经过的时间,单位是秒。
3. time: memcached服务器所在主机当前系统的时间,单位是秒。memcache <wbr>getStats <wbr>参数详解
4. version: memcached组件的版本。这里是我当前使用的1.2.6。
5. pointer_size:服务器所在主机操作系统的指针大小,一般为32或64.
6. curr_items:表示当前缓存中存放的所有缓存对象的数量。不包括目前已经从缓存中删除的对象。
7. total_items:表示从memcached服务启动到当前时间,系统存储过的所有对象的数量,包括目前已经从缓存中删除的对象。
8. bytes:表示系统存储缓存对象所使用的存储空间,单位为字节。
9. curr_connections:表示当前系统打开的连接数。
10. total_connections:表示从memcached服务启动到当前时间,系统打开过的连接的总数。
11. connection_structures:表示从memcached服务启动到当前时间,被服务器分配的连接结构的数量,这个解释是协议文档给的,具体什么意思,我目前还没搞明白。
12. cmd_get:累积获取数据的数量,这里是3,因为我测试过3次,第一次因为没有序列化对象,所以获取数据失败,是null,后边有2次是我用不同对象测试了2次。
13. cmd_set:累积保存数据的树立数量,这里是2.虽然我存储了3次,但是第一次因为没有序列化,所以没有保存到缓存,也就没有记录。
14. get_hits:表示获取数据成功的次数。
15. get_misses:表示获取数据失败的次数。
16. evictions:为了给新的数据项目释放空间,从缓存移除的缓存对象的数目。比如超过缓存大小时根据LRU算法移除的对象,以及过期的对象。
17. bytes_read:memcached服务器从网络读取的总的字节数。
18. bytes_written:memcached服务器发送到网络的总的字节数。
19. limit_maxbytes:memcached服务缓存允许使用的最大字节数。这里为67108864字节,也就是是64M.与我们启动memcached服务设置的大小一致。
20. threads:被请求的工作线程的总数量。这个解释是协议文档给的,具体什么意思,我目前还没搞明白。
总结:stats命令总体来说很有用,通过这个命令我们很清楚当前memcached服务的各方面的信息。除此之外,我还没有其他方法可以知道这些状态信息。可能还有其他途径,可能我对memcached组件还不太熟悉吧。
gerVersion