Memcache入门
memcached介绍
memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。它可以应对任意多个连接,使用非阻塞的网络IO。由于它的工作机制是在内存中开辟一块空间,然后建立一个HashTable,memcached自管理这些HashTable。为什么会有Memcache和memcached两种名称?
其实memcache是这个项目的名称,而memcached是它服务器端的主程序文件名。Memcache在高并发的情况下通过将热数据缓存到内存中来降低数据库的压力,这是目前很多网站使用Memcache的原因。
memcached的安装使用
安装Memcache
memcached的安装非常简单,去官方网站下载http://memcached.org/downloads最新的memcached资源,安装方式很简单,官方例子。唯一比较不能接受的一点是,城外的网都比较慢
wget http://memcached.org/latest
tar -zxvf memcached-1.x.x.tar.gz
cd memcached-1.x.x
./configure && make && make test && sudo make install
启动memcached服务
进入到memcached的安装目录,然后通过daemon的方式启动
起来。
localhost:Downloads MLS$ cd memcached-1.4.23
localhost:memcached-1.4.23 MLS$ ./memcached -d
检查memcached进程
是否已经启动起来:
localhost:memcached-1.4.23 MLS$ ps -ef | grep memcached | grep -v grep
501 6978 1 0 9:37下午 ?? 0:00.01 ./memcached -d
可以看到memcached服务以daemon的形式在后台运行,我们并没有制定端口和IP。memcached默认的端口11211,默认的IP就是本机地址127.0.0.1。当然memcached还给我们分配了默认的内存空间。
Linux下试玩memcached
我们可以使用telnet进入memcached
的运行环境,进入之后就可以对memcached进行基本的操作了
localhost:memcached-1.4.23 MLS$ telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
注意,退出命令是quit
加回车
memcached基本命令的格式
注意,存活时间的单位是秒,0表示永久不过期,
操作命令包括以下操作:set
表示按照相应的存储该数据,没有的时候增加,有的覆盖。add
表示按照相应的添加该数据,但是如果该已经存在则会操作失败。replace
表示按照相应的替换数据,但是如果该不存在则操作失败get
获取一个key为name的数据delete
删除一个key为name的数据,返回DELETED表示删除成功
set操作
set操作注意最后一个表示字节长度的限制,如果设置的值得长度和实现指定的不符合,将抛出ERROR;如果返回STORED表示存储成功
set name 0 0 7
zhongyx
STORED
注意指定长度的时候要严格限制,比如下面这个命令就会发生错误
set key1 0 0 7
yongxiongzhong
CLIENT_ERROR bad data chunk
ERROR
get操作
比如获取一个key为name的数据
get name
VALUE name 0 7
zhongyx
END
delete操作
删除一个key为name的数据,返回DELETED表示删除成功
delete name
DELETED
replace操作
进行replace操作的时候,一定要确保已经设定过该key的缓存值,否则会返回一个错误,假设name是存在的情况
replace name 0 0 7
yongxio
STORED
当尝试去replace一个不存在的值时候
replace name1 0 0 7
zhongyx
NOT_STORED
在PHP中使用memcached
memcached的命令模式已经熟悉的差不多了,但是,最终我们是需要将memcached的服务接入到我们的实际应用中,由于本人就是基于php的web开发,所以本人是在PHP的环境中使用memcached服务。整个安装过程有点繁琐
安装依赖库
https://launchpad.net/libmemcached/1.0/1.0.4/+download/libmemcached-1.0.4.tar.gz
tar -xzvf libmemcached-1.0.4.tar.gz
cd libmemcached-1.0.4
./configure && make && make install
安装memcached扩展
这里采用php扩展库里面的资源。http://pecl.php.net/get/memcached-2.0.1.tgz下载
tar vxzf memcached-2.0.1.tgz
cd memcache-2.0.1
phpize
./configure && make && make install
装完后,最后显示Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20121212/,在该目录下生成memcached.so
我的so文件/usr/lib/php/extensions/no-debug-non-zts-20121212/memcached.so
php配置文件中加入memcached扩展
修改php.ini文件,添加memcached扩展php.ini文件最后一行添加以下代码
extension=/usr/lib/php/extensions/no-debug-non-zts-20121212/memcached.so
重启php,如果安装成功,可以访问phpinfo看到以下界面
php中使用memcached服务
在php中使用memcached非常简单,如果安装了memcached扩展,直接在php中new Memcached
之后就可以正式使用memcached服务了,在实际应用中,一般是set
和get
为主
<?php
$mc = new Memcached();
$mc->addServer("localhost", 11211);
$mc->set("foo", "Hello!");
$mc->set("bar", "Memcached...");
$arr = array(
$mc->get("foo"),
$mc->get("bar")
);
var_dump($arr);
?>
第一个memcached应用例子
在早些年,不知道现在还有没有这种使用方法,看到php的相关教程中有以下使用例子,缓存是做在数据库层,也就是缓存的key是SQL语句的md5值,当需要从数据库中区数据的时候,需要看下memcached中时候有数据,如果通过取数据的SQL命中缓存,则直接返回结果。
<?php
$sql = "select * from user where id={$_GET['uid']}";
//检查缓存
$mc = new Memcached();
$mc->addServer("localhost", 11211);
$row = $mc -> get(md5($sql))
if($row){
return $row;
}
//查询数据库
$conn = new mysql('localhost', '3306', 'root', '123456');
....//此处省略数据库查询
$mc->set(md5($sql), $row);
这种方式应该算是一种最简单的方式了,比较简单,不过这种方式也有它的缺点
- 现在的数据库操作一般都采用PDO方式的预处理语句
- select * 和 select username会存储不一样的缓存中,结果冗余,而且命中率低
- 很难排查问题,获取缓存的key比较难
第二个memcached的应用例子
目前比较多的缓存放在业务层,通过业务逻辑去缓存内容,比如缓存一个用户的数据,是通过uid为维度的缓存,和SQL没有任何关系。这样可以带来好处
- 缓存变得好管理,一个uid就一个缓存数据
- 命中率增高,因为参数变成了一个uid
- 可以很容易的知道用户缓存的key
所在这这种缓存的模型里面,维护将变得更加便捷,下面这个例子和上面的例子有点差别
<?php
$id = $_GET['uid'];
$key = 'USER:UID:'.$id;//一般会加缓存前缀
$mc = new Memcached();
$mc->addServer("localhost", 11211);
$row = $mc->get($key);
if($row){
return $row;
}
//继续走数据库逻辑,并将数据写入mc
$row->set($key, $row);
memcached服务集群
为什么要使用集群
在一些简单的网站中,如果仅仅是为了加速网站,那单台memcached服务挂了问题也不大。但是,如果网站的访问量特别大,当memcached服挂掉了,大量的读操作直接奔向DB,那数据库肯定会奔溃掉。在稍微稳定的网站中,是绝对不允许单点故障的。所以,如果需要构建一个稳定的缓存服务,必须
- 避免单点故障,服务要始终是可用的
- 提升缓存服务的响应速度
需要一个代理
在一个大型的memcached服务集群中,少则几个memcached服务的IP地址,多则几十个memcached服务的IP地址。假如一共有20台机器提供memcached服务,加入一台服务挂了怎么办,加入需要换掉其中的10台服务怎么办,假如需要做到自动摘除挂掉的服务怎办。很显然,让应用层去处理这些情况很不实际,所以我们需要一个中间层,来自twitter的工程师为我们解决了这个问题。他们开发了代理memcached的twemproxy,目前我们团队正在使用的nutcraker
nutcraker的使用
下载安装nutcraker
下载地址:https://twemproxy.googlecode.com/files/nutcracker-0.3.0.tar.gz。
解压之后,运行安装命令
cd nutcracker-0.3.0/
./configure
make && make install
配置nutcracker
配置文件在conf/nutcracker.yml
beta:
listen: 127.0.0.1:22122 #nutcraker代理监听的端口
hash: fnv1a_64 #hase算法
hash_tag: "{}"
distribution: ketama
auto_eject_hosts: false #是否在节点无法响应的时候临时找出,区分save data的slave和cache data的slave
timeout: 400 #超时
servers: #配置真正的mc存储
- 127.0.0.1:6380:1 server1
- 127.0.0.1:6381:1 server2
- 127.0.0.1:6382:1 server3
- 127.0.0.1:6383:1 server4
这个配置表示127.0.0.1:22122这个端口的nutcraker服务代理了servers的4台正真的memcache存储,这个4台memcached服务分别为
- 127.0.0.1:6380:1
- 127.0.0.1:6381:1
- 127.0.0.1:6382:1
- 127.0.0.1:6383:1
也就是说在应用层,只有127.0.0.1:22122
这个接口暴露给我们去使用memcached服务了,我们不关系这个服务下操纵了多少台正真的memcached服务
启动nutcraker服务
采用daemon的方式运行,如果你是用memcache测试的话,注意将配置文件中的redis:true注释掉
#启动
localhost:memcached-1.4.23 MLS$ src/nutcracker -d
#查看
localhost:memcached-1.4.23 MLS$ ps -ef | grep nutcracker
501 17738 1 0 2:26下午 ?? 0:00.01 src/nutcracker -d
501 19559 580 0 2:54下午 ttys002 0:00.00 grep nutcracker
启动4台真正的memcached服务
如果只启动nutcracker服务是没有用的,它只是一个代理,西部要把nutcracker代理的正真的memcached服务起来,才能正常工作运转,其中方法如下
启动4台memcache服务
localhost:memcached-1.4.23 MLS$ ./memcached -d -p 6380;./memcached -d -p 6381;./memcached -d -p 6382;./memcached -d -p 6383
#查看
localhost:memcached-1.4.23 MLS$ ps -ef | grep memcached
501 17541 1 0 2:23下午 ?? 0:00.03 ./memcached -d -p 6380
501 17580 1 0 2:24下午 ?? 0:00.03 ./memcached -d -p 6381
501 17585 1 0 2:24下午 ?? 0:00.03 ./memcached -d -p 6382
501 17587 1 0 2:24下午 ?? 0:00.03 ./memcached -d -p 6383
测试nutcraker服务
连接nutcraker服务并且向nutcraker服务代理写一个数据
localhost:nutcracker-0.3.0 MLS$ telnet 127.0.0.1 22122
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
set key1 0 0 5
hello
STORED
存储是分布式的,并不是每一台真正的memcached服务上都有数据,而是命中其中的一台,然后将数据缓存起来,通过去每台memcached服务查看数据可以看到
6380端口
localhost:memcached-1.4.23 MLS$ telnet 127.0.0.1 6380
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get key1
VALUE key1 0 5
hello
END
6381端口
localhost:memcached-1.4.23 MLS$ telnet 127.0.0.1 6381
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get key1
END
6382端口
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get key1
END
6383端口
localhost:memcached-1.4.23 MLS$ telnet 127.0.0.1 6383
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get key1
END