一、 Introduction
memcache是一套分布式的高速缓存系统。
memcache与redis的联系与区别。
联系,数据都存储在内存当中;数据类型都是key-value。
区别,memcache,每个key的数据最大是1M;对各种技术支持比较全面,比如,session可以存储memcache中,各种框架,比如thinkphp,对memcache的支持比较好;比较老牌,传统的内存缓存技术;适合存储简单实用的数据;数据类型只有string;没有持久化
redis,每个key的数据最大是1G;对各种技术支持没有memcache更好;新兴的内存缓存技术;适合集合计算(list/set/sortset);数据类型丰富(string/list/set/sortset/hash);有持久化
两种内存都重要,都有擅长的地方。memcache对session、框架支持;redis擅长集合计算。互相难以取代。
二、 安装与开启服务
解压win版的memcached,将执行文件拷贝到某个盘符路径下,便于使用cmd查找。
开启memcache服务,在cmd中,e:,进入e盘,然后,memcached,是在前台开启服务,一般不这样开启。memcache –help,调出命令参数。
memcache -p 11213 -l 127.0.0.1 -m 128m 端口11213,监听本机ip,一共使用128m开启memcache。
设置开机启动项。安装开机启动项,memcached -d install。卸载开机启动项,memcached -d uninstall。如果需要在安装开机启动项时设置其他参数,可以memcached -d install -p xxx -l xxx -m xxx …。
启动memcache,可以在计算机右键,管理选项框中启动,也可以通过cmd命令,memcached -d start,关闭服务,memcached -d stop。
三、 php使用memcache
首先,给php开启memcache的扩展extension=php_memcache.dll。如果在php的ext目录下没有php_memcache.dll文件,将这个文件拷贝到ext目录下。重启apache。
php操作memcache
在php中memcache体现为类,具体使用,实例化对象,对象调用成员方法。
1. 具体操作
设置$obj -> set(key,value,是否有压缩,有效期);//是否压缩,不考虑速度,考虑空间,就压缩,否则不。有效期,单位为秒。
获取$obj -> get(key);
删除$obj -> delete(key);
比如:
<?php
//php对memcache的操作
//1,实例化memcache对象
$mem = new Memcache();
//2,连接memcache服务器
$flag = $mem -> connect('localhost',11211);
//3,给内存设置key
$mem -> set('name','haha',0,3600*12);
<?php
//php对memcache的操作
//1,实例化memcache对象
$mem = new Memcache();
//2,连接memcache服务器
$flag = $mem -> connect('localhost',11211);
//3,读取设置的key
var_dump($mem -> get('name'));
注意,关于有效期,为0即不失效。key的名字组成比较随意,不能超过250字节,utf-8字符集的一个汉字是3个字节。有效期有两种方式,时间戳,时间差,一个时间数字,从目前往后延伸的时间长度。为了防止时间差与时间戳混淆,时间差不能超过30天,否则为时间戳。
//3,给内存设置key
$mem -> set('name','haha',0,30);
echo time();
$mem -> set('age',12,0,30,time()+100);
2. 各种数据类型的存储
php的数据类型,基本类型,int,string,boolean,float;复合类型,array,object,resource,null。
<?php
//php对memcache的操作
//1,实例化memcache对象
$mem = new Memcache();
//2,连接memcache服务器
$flag = $mem -> connect('localhost',11211);
//3,给内存设置key
$mem -> set('name','haha',0);
$mem -> set('age',12,0,0);
$mem -> set('eat',false,0);
$mem -> set('pai',3.14,0);
$user = array('usr1'=>'haha1','usr2'=>'hewh','usr3'=>'hlle');
class Student{
var $name ="hee";
var $height = 123;
function eat(){
echo "zaichi";
}
}
$stu = new Student();
$mem -> set('arr',$user,0);
$mem -> set('stu',$stu,0);
$mem -> set('kong',null,0);
<?php
//php对memcache的操作
//1,实例化memcache对象
$mem = new Memcache();
//2,连接memcache服务器
$flag = $mem -> connect('localhost',11211);
//3,读取设置的key
//基本数据类型
var_dump($mem -> get('name'));
var_dump($mem -> get('age'));
var_dump($mem -> get('eat'));
var_dump($mem -> get('pai'));
//复合数据类型
var_dump($mem -> get('arr'));
var_dump($mem -> get('stu'));
var_dump($mem -> get('kong'));
3. 其他相关操作方法
add()//给memcache增加一个key,不存在就增加,存在就报错
set()//给memcache设置key,不存在就增加,存在就修改
close()//关闭memcache连接,一般设置到php代码的最后
decrement()//给key值减1
increment()//给key值加1
flush()//清空memcache的全部key
replace()//替换key的值为其他值,存在替换,不存在就报错
更多方法参考mamual。
四、 终端命令方式操作
登陆到memcache的操作终端,使用telnet远程登陆协议
telnet ip port 比如,telnet 127.0.0.1 11211
如果telnet提示不是内部或外部指令,是因为没有开启telnet服务。控制面板中打开或关闭windows功能,勾选telnet客户端。
在终端操作实现memcache的操作
设置,
set key 是否压缩 有效期 数据长度 【回车】
然后输入设置的数据长度的数据
比如set name 0 50 6
回车后,输入hahaha。设置成功,提示stored。
add key 是否压缩 有效期 数据长度 【回车】
然后输入数据
replace key 是否压缩 有效期 数据长度 【回车】
软后数据数据
获取,
get key,比如,get name
获取memcache的统计信息,stats
在php中通过getStats()获得memcache服务器的统计信息。
利用secureCRT一样可以实现对memcache的操作,走telnet协议。
五、 分布式memcache的部署
memcache与redis的不同,是把一台memcache的工作平均分配给多个memcache分担。
每个memcache服务器都是平等的,中间通过算法保障数据的平均分配。php代码的编写还保持原有习惯即可。
key的分配原则,依次轮询、求余。
分布式具体的实施
方案1,在一个服务器里边开启多个memcache服务。
默认的memcache服务器的端口号为11211,多开的话,设置为其他端口就可以多开。比如,打开cmd,在memcached的软件目录下,memcached -p 11212,开启以11212为端口的memcache,类推多开更多。
方案2,可以配置多个服务器,每个服务器里边都运行memcache服务。
部署了分布的memcache后,
<?php
//php对memcache的操作
//1,实例化memcache对象
$mem = new Memcache();
//2,连接memcache服务器(分布式的)
$mem -> addServer('127.0.0.1',11211);
$mem -> addServer('127.0.0.1',11212);
$mem -> addServer('127.0.0.1',11213);
//3,设置key
$mem -> set('te','haha',0);
<?php
//php对memcache的操作
//1,实例化memcache对象
$mem = new Memcache();
//2,连接memcache服务器(分布式的)
$mem -> addServer('127.0.0.1',11211);
$mem -> addServer('127.0.0.1',11212);
$mem -> addServer('127.0.0.1',11213);
//3,获取key
echo $mem -> get('te');
通过终端控制器,telnet 127.0.0.1 端口号 分别打开各个memcache服务器,get te查看保存在哪个服务器。注意,在每个php脚本内部设置数据和获取数据时保持连接服务器的顺序一致,否则数据可能取不到。
六、 缓存丢失
memcache中的key超过有效期,或被系统强制删除掉的等会使缓存丢失
1. 有效期过期
session信息过期,通过懒惰模式给删除的。session是在文件中存储,如果session已经过期,其文件还是存在的,下次有一个用户访问session信息,比如登陆系统。此时已经过期的session有一定几率被删除。这种就是懒惰模式。是被动的。
memcache中key的删除也是懒惰模式。如果key过期,文件还是存在,当再次被获取时,key被删除。
2. 空间不足被强制删除
memcache的可用空间为64MB,如果存储的数据非常多,可以空间不足了。此时仍然可以存储数据,因为memcache内部有LRU机制。least recently use,最近不被使用的数据。内部空间如果不足,就会删除最近不被使用的数据。
如果不想使用LRU机制,就可以设置参数 –M,禁止LRU机制。在开启memcache服务时,比如,memcache -l xxx -p xxxxx -M
七、 session入memcache
传统的session的数据是在硬盘的文件中存储的。该session很大情况用于存储用户的相关信息,用于判断用户是否登陆系统。两个服务器的session是文件形式存储的,它们的session是不能通信的。
如果两个服务器的session是存储在memcache中的,则它们的session可以通信。
比如,在内容分布式部署中,特别是占带宽大的视频网站,一般有多个服务器支撑,当用户登陆后,也许看第一个视频时有服务器1提供,当看第2个视频时由服务器2提供,此时如果没有session通信,则可能提示用户登陆,这样的体验是不好的。或者某些大型购物平台在某些集中购物的节日,某个可能购买这个商品时,有服务器1提供,当购买别的商品时由服务器2提供数据,如果session不通信,就提示用户登陆,导致不好的用户体验。
hadoop大数据也可以做分布式,但是在这种情形下,是大材小用了。将用户登陆的session持久化信息保存在一个memcache服务器里边,这样服务器2、3、4也可以去session读取session信息,就可以保证用户访问服务器的时候无需重复登陆。
session存储在memcache的操作
修改php.ini的session存储设置,
session.save_handler= files
session.save_path= "D:\002php\amp\php5\tmp"
编写php将session保存到memcache
<?php
//实现session在memcache中存储
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");//连接memcache服务器
//正常操作session
session_start();
$_SESSION['username'] = 'haha';
<?php
//实现session在memcache中存储
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");//连接memcache服务器
//正常操作session
session_start();
var_dump($_SESSION['username']);
session保存到memcache中key的名称为session_id的值。
使用php获得session_id,然后通过memcache获得session_id对应的session的内容。
<?php
//实现session在memcache中存储
ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");//连接memcache服务器
//正常操作session
session_start();
var_dump($_SESSION['username']);
echo "<br />";
$memsession = session_id();//获得session_id信息
$mem = new Memcache();
$mem -> connect('localhost',11211);
$sessioncontent = $mem -> get($memsession);
echo $sessioncontent;
如果memcache是分布式的,
<?php
//实现session在memcache中存储
ini_set("session.save_handler","memcache");
//ini_set("session.save_path","tcp://127.0.0.1:11211");//连接memcache服务器
//分布式memcache的设置
ini_set("session.save_path","tcp://127.0.0.1:11211;tcp://127.0.0.1:11212;tcp://127.0.0.1:11213");
//正常操作session
session_start();
var_dump($_SESSION['username']);
echo "<br />";
$memsession = session_id();//获得session_id信息
$mem = new Memcache();
$mem -> connect('localhost',11211);
$sessioncontent = $mem -> get($memsession);
echo $sessioncontent;
在获取分布式的memcache的session中的值是只要连接到每个memcache服务器,再获取
//1,实例化memcache对象
$mem = new Memcache();
//2,连接memcache服务器(分布式的)
$mem -> addServer('127.0.0.1',11213);
$mem -> addServer('127.0.0.1',11211);
$mem -> addServer('127.0.0.1',11212);
八、 memcache应用到thinkphp框架的例子
比如在网站前台商品列表页面,给商品列表信息存储在memcache中,这样许多人在访问时候就通过memcache获得数据,提高页面的请求速度,降低数据库开销。
在tp中使用memcache缓存,使用S()函数进行缓存的操作。
S(array(‘type’=>’memcache’,’host’=>主机名,’port’=>端口号码));
操作key
S(key,value,有效期);
获取key
S(key);
删除key
S(key,null);
比如:
//列表展示
public function showlist(){
//设置memcache缓存
S(array('type'=>'memcache','host'=>"localhost",'port'=>11211));
//给存储的商品信息设置一个名字,goods_category_info
//线上产品给key其名字,是md5(sql语句)
$info = S("goods_category_info");
if(empty($info)){
//获得商品列表信息
echo "从mysql获得数据";
$info=D("Goods")->order('goods_iddesc')->field("goods_name,goods_price,goods_small_img")->select();
//var_dump($info);die;
//把获得的信息存储在memcache中
S("goods_category_info",$info,0);
}
$this->assign("info",$info);
$this->display();//没有传参,视图模版名称与当前操作方法名称一致
}
如果数据库的数据有修改,就要删除旧的缓存,根据新的数据内容生成新的缓存。或者直接删除旧的缓存,等前台第一次获取数据时,生成新的缓存也可以。
比如后台的商品管理控制器中,增删改操作都要做相应的处理
public functionupd($goods_id){
$goods = D('Goods');
//dump($goods_id);
// dump($height);
// dump($addr);
//find()方法获得数据表记录,每次通过一维数组返回一个记录结果
//$model对象->find();没有设置参数获得第一条结果
//$model对象->find(数字);获得主键为参数值的记录结果
// $info = D('Goods')-> select($goods_id);
// 两个业务逻辑,展示和收集
if (!empty($_POST)) {
$z = $goods-> save($_POST);
//获得全部的商品信息,给前台页面制作新缓存,删除旧缓存
S(array('type'=>'memcache','host'=>"localhost",'port'=>11211));
$info =D("Goods")->order('goods_iddesc')->field("goods_name,goods_price,goods_small_img")->select();
//把获得的信息存储在memcache中
S("goods_category_info",$info,0);
//或者直接删除旧的缓存也可以
//S("goods_category_info",null);
if ($z) {
//页面跳转
//$this->redirect(分组/控制器/操作方法,参数array,间隔时间,提示信息);
// $this ->redirect("showlist",array(), 2, '数据添加成功');
//如果设置参数,可以get方法传递,比如
$this ->redirect("showlist",array(), 2, '数据修改成功');
} else {
$this ->redirect("upd",array('goods_id' => $goods_id), 2, '数据修改失败');
}
} else {
$info = D('Goods')-> find($goods_id);
$this ->assign('info', $info);
$this ->display();
}
}