memcache

1、memcache的概念?

Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。简单的说就是将数据调用到内存中,然后从内存中读取,从而大大提高读取速度。在动态系统中减少数据库负载,提升性能。

memcache模块是一个高效的守护进程,提供用于内存缓存的过程式程序和面向对象的方便的接口,特别是对于设计动态web程序时减少对数据库的访问

2:作用:它可以应对任意多个连接,使用非阻塞的网络IO。由于它的工作机制是在内存中开辟一块空间,然后建立一个HashTable,Memcached自管理这些HashTable。

3:Memcache官方网站:http://www.danga.com/memcached,更多详细的信息可以来这里了解 :)
为什么会有Memcache和memcached两种名称?
其实Memcache是这个项目的名称,而memcached是它服务器端的主程序文件名。一个是项目名称,一个是主程序文件名,在网上看到了很多人不明白,于是混用了。

4:适用场合

1)分布式应用。由于memcached本身基于分布式的系统,所以尤其适合大型的分布式系统。
2)数据库前段缓存。数据库常常是网站系统的瓶颈。数据库的大并发量访问,常常造成网站内存溢出。当然我们也可以使用Hibernate的缓存机制。但memcached是基于分布式的,并可独立于网站应用本身,所以更适合大型网站进行应用的拆分。
3)服务器间数据共享。举例来讲,我们将网站的登录系统、查询系统拆分为两个应用,放在不同的服务器上,并进行集群,那这个时候用户登录后,登录信息如何从登录系统服务器同步到查询系统服务器呢?这时候,我们便可以使用memcached,登录系统将登录信息缓存起来,查询系统便可以获得登录信息,就像获取本地信息一样。

5:不适用场合

那些不需要“分布”的,不需要共享的,或者干脆规模小到只有一台服务器的应用,memcached不会带来任何好处,相反还会拖慢系统效率,因为网络连接同样需要资源

memcached安装

【memcached 安装使用windows 】
先把php版本从5.2.0升级到5.2.4(覆盖原来的文件就行了)

  1. http://jehiah.cz/projects/memcached-win32/ 上下载memcache的windows稳定版,解压放某个盘下面,比如在c:\memcached
    2.在终端(也即cmd命令界面)下输入 'c:\memcached\memcached.exe -d install' 安装
    3.再输入: 'c:\memcached\memcached.exe -d start' 启动
    NOTE: 以后memcached将作为windows的一个服务每次开机时自动启动。默认端口:11211。

  2. 在C:\winnt\php.ini 加入一行 'extension=php_memcache.dll'
    [Memcache]
    memcache.allow_failover = 1
    memcache.max_failover_attempts=20
    memcache.chunk_size =8192
    memcache.default_port = 11211

  3. 下载pecl的PECL 5.2.4 Win32 binaries模块包,解压缩后将其中的memcache.dll考到c:\php\ext 中,(也不一定是c盘的PHP文件夹下,主要是看你当初把PHP安装到哪个盘符下面了)
    NOTE: php和pecl的版本要一致。
    6.重新启动Apache,然后查看一下phpinfo,如果有memcache,那么就说明安装成功!
    注:memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。
    Memcache官方网站:http://www.danga.com/memcached
    扩展下载: http://pecl4win.php.net/download.php/ext/5_1/5.1.2/php_memcache.dll
    【安装Memcache服务器端linux】
    我目前的平台,服务器是Fedora Core 1(内核:2.4.22),客户端是Windows XP SP2,需要安装的就是服务器的Memcached的守护进程和客户端的PHP扩展php_memcache两个东西。现在我分别来讲。
    服务器端主要是安装memcache服务器端,目前的最新版本是 memcached-1.2.0 。
    下载:http://www.danga.com/memcached/dist/memcached-1.2.0.tar.gz
    另外,Memcache用到了libevent这个库用于Socket的处理,所以还需要安装libevent,libevent的最新版本是libevent-1.2。(如果你的系统已经安装了libevent,可以不用安装)
    官网:http://www.monkey.org/~provos/libevent/
    下载:http://www.monkey.org/~provos/libevent-1.2.tar.gz
    我分别把两个东东下载回来,放到 /tmp 目录下:

cd /tmp

wget http://www.danga.com/memcached/dist/memcached-1.2.0.tar.gz

wget http://www.monkey.org/~provos/libevent-1.2.tar.gz

先安装libevent:

tar zxvf libevent-1.2.tar.gz

cd libevent-1.2

./configure --prefix=/usr

make

make install

然后看看我们的libevent是否安装成功:

ls -al /usr/lib | grep libevent

lrwxrwxrwx 1 root ??? root ?? ?? 21 11?? 12 17:38 libevent-1.2.so.1 -> libevent-1.2.so.1.0.3
-rwxr-xr-x ?? 1 root ??? root ?? ?? 263546 11?? 12 17:38 libevent-1.2.so.1.0.3
-rw-r--r-- ?? ??? 1 root ??? root ?? ?? 454156 11?? 12 17:38 libevent.a
-rwxr-xr-x ?? 1 root ??? root ?? ?? 811 11?? 12 17:38 libevent.la
lrwxrwxrwx 1 root ??? root ?? ?? 21 11?? 12 17:38 libevent.so -> libevent-1.2.so.1.0.3
还不错,都安装上了,再来安装memcache,同时需要安装中指定libevent的安装位置:

cd /tmp

tar zxvf memcached-1.2.0.tar.gz

cd memcached-1.2.0

./configure --with-libevent=/usr

make

make install

如果中间出现报错,请仔细检查错误信息,按照错误信息来配置或者增加相应的库或者路径。

安装完成后会把memcached放到 /usr/local/bin/memcached ,我们看以下是否安装了:

ls -al /usr/local/bin/mem*

-rwxr-xr-x 1 root ??? root ?? 137986 11?? 12 17:39 /usr/local/bin/memcached
-rwxr-xr-x 1 root ??? root ?? 140179 11?? 12 17:39 /usr/local/bin/memcached-debug
恩,安装完成了,现在我们看以下memcache的帮助:

/usr/local/bin/memecached -h

memcached 1.2.0
-p <num> 是设置Memcache监听的端口,这里设置了12000,最好是1024以上的端口
-s <file> unix socket path to listen on (disables network support)
-l <ip_addr> 连接的IP地址, 默认是本机 是监听的服务器IP地址,如果有多个地址的话,这里指定了服务器的IP地址192.168.0.122
-d 以守护程序(daemon)方式运行 memcached
-r maximize core file limit
-u 以的身份运行 (仅在以root运行的时候有效)<username> assume identity of <username> (only when run as root)
-m <num>最大内存使用,单位MB。默认64MB max memory to use for items in megabytes, default is 64 MB是分配给Memcache使用的内存数量,单位是MB,这里是10MB
-M内存耗尽时返回错误,而不是删除项return error on memory exhausted (rather than removing items)
-c <num> 选项是最大运行的并发连接数,默认是1024,这里设置了256,按照你服务器的负载量来设定
-k lock down all paged memory
-v verbose (print errors/warnings while in event loop)
-vv very verbose (also print client commands/reponses)
-h 显示帮助<-->print this help and exit
-i print memcached and libevent license
-b run a managed instanced (mnemonic: buckets)
-P <file> save PID in <file>, only used with -d option是设置保存Memcache的pid文件
-f <factor> 块大小增长因子,默认是1.25chunk size growth factor, default 1.25
-n <bytes> ?? ?最小分配空间,key+value+flags默认是48minimum space allocated for key+value+flags, default 48

常用命令:

-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
netstat –an
参数不算多,我们来启动一个Memcache的服务器端:

/usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 12000 -c 256 -P tmp/memcached.pid

-d选项是启动一个守护进程,-m是分配给Memcache使用的内存数量,单位是MB,我这里是10MB,-u是运行Memcache的用户,我这里是root,-l是监听的服务器IP地址,如果有多个地址的话,我这里指定了服务器的IP地址192.168.0.200,-p是设置Memcache监听的端口,我这里设置了12000,最好是1024以上的端口,-c选项是最大运行的并发连接数,默认是1024,我这里设置了256,按照你服务器的负载量来设定,-P是设置保存Memcache的pid文件,我这里是保存在/tmp/memcached.pid,如果要结束Memcache进程,执行:

kill cat /tmp/memcached.pid

【Memcache初试】

写一个 example.php 文件(更多使用方法可以参看 PHP 手册里的 Memcache Functions 使用说明),测试代码如下:

<?php

$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");

$version = $memcache->getVersion();
echo "Server's version: ".$version."
\n";

$tmp_object = new stdClass;
$tmp_object->str_attr = 'test';
$tmp_object->int_attr = 123;

$memcache->set('key', $tmp_object, false, 10) or die ("Failed to save data at the server");
echo "Store data in the cache (data will expire in 10 seconds)
\n";

$get_result = $memcache->get('key');
echo "Data from the cache:
\n";

var_dump($get_result);

?>

如果输出如下,则测试成功:

Server's version: 1.4.5
Store data in the cache (data will expire in 10 seconds)
Data from the cache:
object(stdClass)#3 (2) { ["str_attr"]=> string(4) "test" ["int_attr"]=> int(123) }

[ 接口介绍 ]
服务器端和客户端都安装配置好了,现在我们就来测试以下我们的成果。Memcache客户端包含两组接口,一组是面向过程的接口,一组是面向对象的接口,具体可以参考PHP手册 “LXXV. Memcache Functions”这章。我们为了简单方便,就使用面向对象的方式,也便于维护和编写代码。Memcache面向对象的常用接口包括:
Memcache::connect -- 打开一个到Memcache的连接
Memcache::pconnect -- 打开一个到Memcache的长连接
Memcache::close -- 关闭一个Memcache的连接
Memcache::set -- 保存数据到Memcache服务器上
Memcache::get -- 提取一个保存在Memcache服务器上的数据
Memcache::replace -- 替换一个已经存在Memcache服务器上的项目(功能类似Memcache::set)
Memcache::delete -- 从Memcache服务器上删除一个保存的项目
Memcache::flush -- 刷新所有Memcache服务器上保存的项目(类似于删除所有的保存的项目)
Memcache::getStats -- 获取当前Memcache服务器运行的状态
[ 测试代码 ]
现在我们开始一段测试代码:

<?php
//连接
$mem=new Memcache;
$mem->connect("192.168.0.200",12000);

//保存数据
$mem->set('key1','This is first value',0,60);
$val=$mem->get('key1');
echo
"Get key1 value: "
.
$val
."
";

//替换数据
$mem->replace('key1','This is replace value',0,60);
$val=$mem->get('key1');
echo
"Get key1 value: "
.
$val
.
"
";

//保存数组
$arr
=
array('aaa','bbb','ccc','ddd');
$mem->set('key2',$arr,0,60);
$val2=$mem->get('key2');
echo
"Get key2 value: ";
print_r($val2);
echo
"
";

//删除数据
$mem->delete('key1');
$val=$mem->get('key1');
echo
"Get key1 value: "
.
$val
.
"
";

//清除所有数据
$mem->flush();
$val2=$mem->get('key2');
echo
"Get key2 value: ";
print_r($val2);
echo
"
";

//关闭连接
$mem->close();
?>

如果正常的话,浏览器将输出:
Get key1 value: This is first value
Get key1 value: This is replace value
Get key2 value: Array ( [0] => aaa [1] => bbb [2] => ccc [3] => ddd )
Get key1 value:
Get key2 value:

基本说明我们的Memcache安装成功,我们再来分析以下上面的这段程序。

[ 程序分析 ]
初始化一个Memcache的对象:
$mem = new Memcache;
连接到我们的Memcache服务器端,第一个参数是服务器的IP地址,也可以是主机名,第二个参数是Memcache的开放的端口:
$mem->connect("192.168.0.200", 12000);
保存一个数据到Memcache服务器上,第一个参数是数据的key,用来定位一个数据,第二个参数是需要保存的数据内容,这里是一个字符串,第三个参数是一个标记,一般设置为0或者MEMCACHE_COMPRESSED就行了,第四个参数是数据的有效期,就是说数据在这个时间内是有效的,如果过去这个时间,那么会被Memcache服务器端清除掉这个数据,单位是秒,如果设置为0,则是永远有效,我们这里设置了60,就是一分钟有效时间:
$mem->set('key1', 'This is first value', 0, 60);
从Memcache服务器端获取一条数据,它只有一个参数,就是需要获取数据的key,我们这里是上一步设置的key1,现在获取这个数据后输出输出:
$val = $mem->get('key1');
echo "Get key1 value: " . $val;
现在是使用replace方法来替换掉上面key1的值,replace方法的参数跟set是一样的,不过第一个参数key1是必须是要替换数据内容的key,最后输出了:
$mem->replace('key1', 'This is replace value', 0, 60);
$val = $mem->get('key1');
echo "Get key1 value: " . $val;
同样的,Memcache也是可以保存数组的,下面是在Memcache上面保存了一个数组,然后获取回来并输出
$arr = array('aaa', 'bbb', 'ccc', 'ddd');
$mem->set('key2', $arr, 0, 60);
$val2 = $mem->get('key2');
print_r($val2);
现在删除一个数据,使用delte接口,参数就是一个key,然后就能够把Memcache服务器这个key的数据删除,最后输出的时候没有结果
$mem->delete('key1');
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "
";
最后我们把所有的保存在Memcache服务器上的数据都清除,会发现数据都没有了,最后输出key2的数据为空,最后关闭连接
$mem->flush();
$val2 = $mem->get('key2');
echo "Get key2 value: ";
print_r($val2);
echo "
";

【socket操作memcached】

下面是一段简单的测试代码,代码中对标识符为 'mykey' 的对象数据进行存取操作:
<?php
// 包含 memcached 类文件
require_once('memcached-client.php');
// 选项设置
$options = array(
'servers' => array('192.168.1.1:11211'), //memcached 服务的地址、端口,可用多个数组元素表示多个 memcached 服务
'debug' => true, //是否打开 debug
'compress_threshold' => 10240, //超过多少字节的数据时进行压缩
'persistant' => false //是否使用持久连接
);
// 创建 memcached 对象实例
$mc = new memcached($options);
// 设置此脚本使用的唯一标识符
$key = 'mykey';
// 往 memcached 中写入对象
$mc->add($key, 'some random strings');
$val = $mc->get($key);
echo "n".str_pad('$mc->add() ', 60, '')."n";
var_dump($val);
// 替换已写入的对象数据值
$mc->replace($key, array('some'=>'haha', 'array'=>'xxx'));
$val = $mc->get($key);
echo "n".str_pad('$mc->replace() ', 60, '
')."n";
var_dump($val);
// 删除 memcached 中的对象
$mc->delete($key);
$val = $mc->get($key);
echo "n".str_pad('$mc->delete() ', 60, '_')."n";
var_dump($val);
?>

[存储数据库查询结果到memcache]

在实际应用中,通常会把数据库查询的结果集保存到 memcached 中,下次访问时直接从 memcached 中获取,而不再做数据库查询操作,这样可以在很大程度上减轻数据库的负担。通常会将 SQL 语句 md5() 之后的值作为唯一标识符 key。下边是一个利用 memcached 来缓存数据库查询结果集的示例(此代码片段紧接上边的示例代码):
复制代码 代码如下:

<?php
$sql = 'SELECT * FROM users';
$key = md5($sql); //memcached 对象标识符
if ( !($datas = $mc->get($key)) ) {
// 在 memcached 中未获取到缓存数据,则使用数据库查询获取记录集。
echo "n".str_pad('Read datas from MySQL.', 60, '')."n";
$conn = mysql_connect('localhost', 'test', 'test');
mysql_select_db('test');
$result = mysql_query($sql);
while ($row = mysql_fetch_object($result))
$datas[] = $row;
// 将数据库中获取到的结果集数据保存到 memcached 中,以供下次访问时使用。
$mc->add($key, $datas);
} else {
echo "n".str_pad('Read datas from memcached.', 60, '
')."n";
}
var_dump($datas);
?>

可以看出,使用 memcached 之后,可以减少数据库连接、查询操作,数据库负载下来了,脚本的运行速度也提高了。

【Memcache协议分析】
如果你不喜欢 php_memcache.dll 扩展或者服务器器目前不支持这个扩展,那么就可以考虑自己构建,需要构建Memcahe的客户端,要先了解Memcache协议的交互,这样才能开发自己的客户端,我这里就简单的分析以下Memcache的协议。
(更详细的协议内容请在Memcache服务器端的源码的 doc/protocol.txt 文件中,本文基本来源于此)
Memcache既支持TCP协议,也支持UDP协议,不过我们这里是以TCP协议的协议作为主要考虑对象,想了解UDP协议的过程,请参考 doc/protocol.txt 文件。
[ 错误指令]
Memcache的协议的错误部分主要是三个错误提示之提示指令:
普通错误信息,比如指令错误之类的 ERROR\r\n
客户端错误CLIENT_ERROR <错误信息>\r\n
服务器端错误SERVER_ERROR <错误信息>\r\n
[ 数据保存指令]
数据保存是基本的功能,就是客户端通过命令把数据返回过来,服务器端接收后进行处理。
指令格式:
<命令> <键> <标记> <有效期> <数据长度>\r\n
<命令> - command name
主要是三个储存数据的三个命令, set, add, replace
set 命令是保存一个叫做key的数据到服务器上
add 命令是添加一个数据到服务器,但是服务器必须这个key是不存在的,能够保证数据不会被覆盖
replace 命令是替换一个已经存在的数据,如果数据不存在,就是类似set功能
<键> - key
就是保存在服务器上唯一的一个表示符,必须是跟其他的key不冲突,否则会覆盖掉原来的数据,这个key是为了能够准确的存取一个数据项目
<标记> - flag
标记是一个16位的无符号整形数据,用来设置服务器端跟客户端一些交互的操作
<有效期> - expiration time
是数据在服务器上的有效期限,如果是0,则数据永远有效,单位是秒,Memcache服务器端会把一个数据的有效期设置为当前Unix时间+设置的有效时间
<数据长度> - bytes
数据的长度,block data 块数据的长度,一般在这个个长度结束以后下一行跟着block data数据内容,发送完数据以后,客户端一般等待服务器端的返回,服务器端的返回:
数据保存成功 STORED\r\n
数据保存失败,一般是因为服务器端这个数据key已经存在了NOT_STORED\r\n

[ 数据提取命令]
从服务器端提取数据主要是使用get指令,格式是:
get <键>\r\n
<键>
- key
key是是一个不为空的字符串组合,发送这个指令以后,等待服务器的返回。如果服务器端没有任何数据,则是返回:
END\r\n
证明没有不存在这个key,没有任何数据,如果存在数据,则返回指定格式:
VALUE <键> <标记> <数据长度>\r\n
<数据块>\r\n
返回的数据是以VALUE开始的,后面跟着key和flags,以及数据长度,第二行跟着数据块。
<键> -key
是发送过来指令的key内容
<标记> - flags
是调用set指令保存数据时候的flags标记
<数据长度> - bytes
是保存数据时候定位的长度
<数据块> - data block
数据长度下一行就是提取的数据块内容

[ 数据删除指令]
数据删除指令也是比较简单的,使用get指令,格式是:
delete <键> <超时时间>\r\n
<键> - key
key是你希望在服务器上删除数据的key键
<超时时间> - timeout
按照秒为单位,这个是个可选项,如果你没有指定这个值,那么服务器上key数据将马上被删除,如果设置了这个值,那么数据将在超时时间后把数据清除,该项缺省值是0,就是马上被删除
删除数据后,服务器端会返回:
DELETED\r\n
删除数据成功
NOT_FOUND\r\n
这个key没有在服务器上找到
如果要删除所有服务器上的数据,可以使用flash_all指令,格式:
flush_all\r\n

这个指令执行后,服务器上所有缓存的数据都被删除,并且返回:
OK\r\n
这个指令一般不要轻易使,除非你却是想把所有数据都干掉,删除完以后可以无法恢复的。

[其他指令]
如果想了解当前Memcache服务器的状态和版本等信息,可以使用状态查询指令和版本查询指令。
如果想了解当前所有Memcache服务器运行的状态信息,可以使用stats指令,格式
stats\r\n
服务器将返回每行按照 STAT 开始的状态信息,包括20行,20项左右的信息,包括守护进程的pid、版本、保存的项目数量、内存占用、最大内存限制等等信息。

如果只是想获取部分项目的信息,可以指定参数,格式:
stats <参数>\r\n
这个指令将只返回指定参数的项目状态信息。
如果只是想单独了解当前版本信息,可以使用version指令,格式:
version\r\n
将返回以 VERSION 开头的版本信息
如果想结束当前连接,使用quit指令,格式:
quit\r\n
将断开当前连接
另外还有其他指令,包括incr, decr 等,我也不太了解作用,就不做介绍了,如果感兴趣,可以自己去研究。

【Memcache在中型网站的使用】
使用Memcache的网站一般流量都是比较大的,为了缓解数据库的压力,让Memcache作为一个缓存区域,把部分信息保存在内存中,在前端能够迅速的进行存取。那么一般的焦点就是集中在如何分担数据库压力和进行分布式,毕竟单台Memcache的内存容量的有限的。我这里简单提出我的个人看法,未经实践,权当参考。
[ 分布式应用]
Memcache本来支持分布式,我们客户端稍加改造,更好的支持。我们的key可以适当进行有规律的封装,比如以user为主的网站来说,每个用户都有UserID,那么可以按照固定的ID来进行提取和存取,比如1开头的用户保存在第一台Memcache服务器上,以2开头的用户的数据保存在第二胎Mecache服务器上,存取数据都先按照User ID来进行相应的转换和存取。
但是这个有缺点,就是需要对User ID进行判断,如果业务不一致,或者其他类型的应用,可能不是那么合适,那么可以根据自己的实际业务来进行考虑,或者去想更合适的方法。
[ 减少数据库压力]
这个算是比较重要的,所有的数据基本上都是保存在数据库当中的,每次频繁的存取数据库,导致数据库性能极具下降,无法同时服务更多的用户,比如MySQL,特别频繁的锁表,那么让Memcache来分担数据库的压力吧。我们需要一种改动比较小,并且能够不会大规模改变前端的方式来进行改变目前的架构。
我考虑的一种简单方法:
后端的数据库操作模块,把所有的Select操作提取出来(update/delete/insert不管),然后把对应的SQL进行相应的hash算法计算得出一个hash数据key(比如MD5或者SHA),然后把这个key去Memcache中查找数据,如果这个数据不存在,说明还没写入到缓存中,那么从数据库把数据提取出来,一个是数组类格式,然后把数据在set到Memcache中,key就是这个SQL的hash值,然后相应的设置一个失效时间,比如一个小时,那么一个小时中的数据都是从缓存中提取的,有效减少数据库的压力。
缺点是数据不实时,当数据做了修改以后,无法实时到前端显示,并且还有可能对内存占用比较大,毕竟每次select出来的数据数量可能比较巨大,这个是需要考虑的因素。
上面只是我两点没有经过深思熟虑的简单想法,也许有用,那就最好了。

【Memcache的安全】
我们上面的Memcache服务器端都是直接通过客户端连接后直接操作,没有任何的验证过程,这样如果服务器是直接暴露在互联网上的话是比较危险,轻则数据泄露被其他无关人员查看,重则服务器被入侵,因为Mecache是以root权限运行的,况且里面可能存在一些我们未知的bug或者是缓冲区溢出的情况,这些都是我们未知的,所以危险性是可以预见的。
为了安全起见,我做两点建议,能够稍微的防止黑客的入侵或者数据的泄露。
[ 内网访问]
最好把两台服务器之间的访问是内网形态的,一般是Web服务器跟Memcache服务器之间。普遍的服务器都是有两块网卡,一块指向互联网,一块指向内网,那么就让Web服务器通过内网的网卡来访问Memcache服务器,我们Memcache的服务器上启动的时候就监听内网的IP地址和端口,内网间的访问能够有效阻止其他非法的访问。

memcached -d -m 1024?? -u root -l 192.168.0.200 -p 11211 -c 1024 -P /tmp/memcached.pid

Memcache服务器端设置监听通过内网的192.168.0.200的ip的11211端口,占用1024MB内存,并且允许最大1024个并发连接

[ 设置防火墙]
防火墙是简单有效的方式,如果却是两台服务器都是挂在网的,并且需要通过外网IP来访问Memcache的话,那么可以考虑使用防火墙或者代理程序来过滤非法访问。
一般我们在Linux下可以使用iptables或者FreeBSD下的ipfw来指定一些规则防止一些非法的访问,比如我们可以设置只允许我们的Web服务器来访问我们Memcache服务器,同时阻止其他的访问。

iptables -F

iptables -P INPUT DROP

iptables -A INPUT -p tcp -s 192.168.0.2 --dport 11211 -j ACCEPT

iptables -A INPUT -p udp -s 192.168.0.2 --dport 11211 -j ACCEPT

上面的iptables规则就是只允许192.168.0.2这台Web服务器对Memcache服务器的访问,能够有效的阻止一些非法访问,相应的也可以增加一些其他的规则来加强安全性,这个可以根据自己的需要来做。

【Memcache的扩展性】
Memcache算是比较简洁高效的程序,Memcache 1.2.0 的源代码大小才139K,在Windows平台上是不可想象的,但是在开源世界来说,这是比较正常合理的。
Memcache目前都只是比较简单的功能,简单的数据存取功能,我个人希望如果有识之士,能够在下面两方面进行扩展。

  1. 日志功能
    目前Memcache没有日志功能,只有一些命令在服务器端进行回显,这样是很不利于对一个服务器的稳定性和负载等等进行监控的,最好能够相应的加上日志的等功能,便于监控。
  2. 存储结构
    目前的数据形式就是: key => data 的形式,特别单一,只能够存储单一的一维数据,如果能够扩展的话,变成类似数据库的格式,能够存储二维数据,那样会让可以用性更强,使用面更广,当然相应的可能代码效率和存取效率更差一些。
  3. 同步功能
    数据同步是个比较重要的技术,因为谁都不能保证一台服务器是持久正常的运行的,如果能够具有类似MySQL的 Master/Slave的功能,那么将使得Memcache的数据更加稳定,那么相应的就可以考虑存储持久一点的数据,并且不用害怕Memcache的down掉,因为有同步的备份服务器,这个问题就不是问题了。
    以上三点只是个人拙见,有识之士和技术高手可以考虑。

【结束语】
我上面的内容都只是自己安装和使用的一些想法,不能保证绝对正确,只是给需要的人一个参考,一个推广Memcache的文章,希望更多的人能够认识和了解这个技术,并且为自己所用。
我花费了整整一个晚上的时间洋洋洒洒的写了这么长,无非是对于这项开源技术的热爱,我想开源世界能够繁荣起来,就是源于大家的热爱并且愿意做出贡献,开源世界才这么精彩。
希望本文能够给需要的人一些帮助,希望不会误导他们,呵呵。
附加:(我操作Memcache相应对应上面文章内容的图片)
[ 启动Memcache]

[ Memcache的PHP测试代码]

[测试代码执行效果]

[ 通过Telnet连接到Memcache ]

[ 基本的Memcache的数据存取协议交互]

[ Memcache状态信息协议交互]

【MemAdmin】
MemAdmin是一款可视化的Memcached管理与监控工具,使用PHP开发,体积小,操作简单。
主要功能:
服务器参数监控:STATS、SETTINGS、ITEMS、SLABS、SIZES实时刷新
服务器性能监控:GET、DELETE、INCR、DECR、CAS等常用操作命中率实时监控支持数据遍历,方便对存储内容进行监视支持条件查询,筛选出满足条件的KEY或VALUE
数组、JSON等序列化字符反序列显示
兼容memcache协议的其他服务,如Tokyo Tyrant (遍历功能除外)
支持服务器连接池,多服务器管理切换方便简洁

高级 memcached 客户机命令

可以在 memcached 中使用的两个高级命令是 gets 和 cas。gets 和 cas 命令需要结合使用。您将使用这两个命令来确保不会将现有的名称/值对设置为新值(如果该值已经更新过)。我们来分别看看这些命令。

gets
gets 命令的功能类似于基本的 get 命令。两个命令之间的差异在于,gets 返回的信息稍微多一些:64 位的整型值非常像名称/值对的 “版本” 标识符。

下面是使用 gets 命令的客户机服务器交互:

set userId 0 0 5
12345
STORED

get userId
VALUE userId 0 5
12345
END

gets userId
VALUE userId 0 5 4
12345
END

考虑 get 和 gets 命令之间的差异。gets 命令将返回一个额外的值 — 在本例中是整型值 4,用于标识名称/值对。如果对此名称/值对执行另一个 set 命令,则 gets 返回的额外值将会发生更改,以表明名称/值对已经被更新。清单 6 显示了一个例子:

清单 6. set 更新版本指示符

set userId 0 0 5
33333
STORED

gets userId
VALUE userId 0 5 5
33333
END

您看到 gets 返回的值了吗?它已经更新为 5。您每次修改名称/值对时,该值都会发生更改。

cas
cas(check 和 set)是一个非常便捷的 memcached 命令,用于设置名称/值对的值(如果该名称/值对在您上次执行 gets 后没有更新过)。它使用与 set 命令相类似的语法,但包括一个额外的值:gets 返回的额外值。

注意以下使用 cas 命令的交互:

set userId 0 0 5
55555
STORED

gets userId
VALUE userId 0 5 6
55555
END

cas userId 0 0 5 6
33333
STORED

如您所见,我使用额外的整型值 6 来调用 gets 命令,并且操作运行非常顺序。现在,我们来看看清单 7 中的一系列命令:

清单 7. 使用旧版本指示符的 cas 命令

set userId 0 0 5
55555
STORED

gets userId
VALUE userId 0 5 8
55555
END

cas userId 0 0 5 6
33333
EXISTS

注意,我并未使用 gets 最近返回的整型值,并且 cas 命令返回 EXISTS 值以示失败。从本质上说,同时使用 gets 和 cas 命令可以防止您使用自上次读取后经过更新的名称/值对。

缓存管理命令

最后两个 memcached 命令用于监控和清理 memcached 实例。它们是 stats 和 flush_all 命令。

stats
stats 命令的功能正如其名:转储所连接的 memcached 实例的当前统计数据。在下例中,执行 stats 命令显示了关于当前 memcached 实例的信息:

stats
STAT pid 63
STAT uptime 101758
STAT time 1248643186
STAT version 1.4.11
STAT pointer_size 32
STAT rusage_user 1.177192
STAT rusage_system 2.365370
STAT curr_items 2
STAT total_items 8
STAT bytes 119
STAT curr_connections 6
STAT total_connections 7
STAT connection_structures 7
STAT cmd_get 12
STAT cmd_set 12
STAT get_hits 12
STAT get_misses 0
STAT evictions 0
STAT bytes_read 471
STAT bytes_written 535
STAT limit_maxbytes 67108864
STAT threads 4
END

此处的大多数输出都非常容易理解。稍后在讨论缓存性能时,我还将详细解释这些值的含义。至于目前,我们先来看看输出,然后再使用新的键来运行一些 set 命令,并再次运行 stats 命令,注意发生了哪些变化。

flush_all
flush_all 是最后一个要介绍的命令。这个最简单的命令仅用于清理缓存中的所有名称/值对。如果您需要将缓存重置到干净的状态,则 flush_all 能提供很大的用处。下面是一个使用 flush_all 的例子:

set userId 0 0 5
55555
STORED

get userId
VALUE userId 0 5
55555
END

flush_all
OK

get userId
END

缓存性能

在本文的最后,我将讨论如何使用高级 memcached 命令来确定缓存的性能。stats 命令用于调优缓存的使用。需要注意的两个最重要的统计数据是 et_hits 和 get_misses。这两个值分别指示找到名称/值对的次数(get_hits)和未找到名称/值对的次数(get_misses)。

结合这些值,我们可以确定缓存的利用率如何。初次启动缓存时,可以看到 get_misses 会自然地增加,但在经过一定的使用量之后,这些 get_misses 值应该会逐渐趋于平稳 — 这表示缓存主要用于常见的读取操作。如果您看到 get_misses 继续快速增加,而 get_hits 逐渐趋于平稳,则需要确定一下所缓存的内容是什么。您可能缓存了错误的内容。

确定缓存效率的另一种方法是查看缓存的命中率(hit ratio)。缓存命中率表示执行 get 的次数与错过 get 的次数的百分比。要确定这个百分比,需要再次运行 stats 命令,如清单 8 所示:

清单 8. 计算缓存命中率

stats
STAT pid 6825
STAT uptime 540692
STAT time 1249252262
STAT version 1.2.6
STAT pointer_size 32
STAT rusage_user 0.056003
STAT rusage_system 0.180011
STAT curr_items 595
STAT total_items 961
STAT bytes 4587415
STAT curr_connections 3
STAT total_connections 22
STAT connection_structures 4
STAT cmd_get 2688
STAT cmd_set 961
STAT get_hits 1908
STAT get_misses 780
STAT evictions 0
STAT bytes_read 5770762
STAT bytes_written 7421373
STAT limit_maxbytes 536870912
STAT threads 1
END

现在,用 get_hits 的数值除以 cmd_gets。在本例中,您的命中率大约是 71%。在理想情况下,您可能希望得到更高的百分比 — 比率越高越好。查看统计数据并不时测量它们可以很好地判定缓存策略的效率。

[常有命令如下:]

启动/结束
memcached -d -m 10 -u root -l 192.168.0.122 -p 11200 -c 256 -P /tmp/memcached.pid
-d 选项是启动一个守护进程,
-m 是分配给Memcache使用的内存数量,单位是MB,这里是10MB
-u 是运行Memcache的用户,这里是root
-l 是监听的服务器IP地址,如果有多个地址的话,这里指定了服务器的IP地址192.168.0.122
-p 是设置Memcache监听的端口,这里设置了12000,最好是1024以上的端口
-c 选项是最大运行的并发连接数,默认是1024,这里设置了256,按照你服务器的负载量来设定
-P 是设置保存Memcache的pid文件
kill cat /tmp/memcached.pid

获取运行状态
echo stats | nc 192.168.1.123 11200
watch "echo stats | nc 192.168.1.123 11200" (实时状态)

1。memcached的连接函数(connect, pconnect)

2。memcahced的操作函数(set, get, delete, replace, flush)

3。多服务器配置函数(addServer)

4。状态监控函数(getStats.....)

[安装多个memcached]
sc create "Memcached Server1" start= auto binPath= "C:\memcached\memcached.exe -d runservice -m 32 -p 11220 -l 127.0.0.1" DisplayName= "Memcached Server1"

下面是启动、停止、卸载该服务的命令:

sc start "Memcached Server1" //启动
sc stop "Memcached Server1" //停止
sc delete "Memcached Server1" //卸载该服务

分布式memcached测试:

<?php

//我的电脑上有两个memcahced服务.

$mem=new Memcache;
$mem->addServer('127.0.0.1',11211);
$mem->addServer('127.0.0.1',11221);
$mem->addServer('127.0.0.1',11220);

//这里注意,把key1,放入到 11211端口的mem还是
//9999 端口的mem就不要我们操心,有$mem对象本身维护.
if($mem->set('key1','hello',MEMCACHE_COMPRESSED,300)){
echo 'add ok!';
}
if($mem->set('key2','hello2',MEMCACHE_COMPRESSED,300)){
echo 'add ok!';
}
if($mem->set('key3','hello3',MEMCACHE_COMPRESSED,300)){
echo 'add ok!';
}

?>
总结:

  1. mem服务的数据不是同步的, 数据是分布的
  2. 把什么数据放入到哪个memcached是由客户端的mem对象决定
  3. 当执行addServer的时候,并不是立即去连接mem服务,而是通过计算,hash后才去决定连接哪个mem服务,因此当你大量加入服务器到连接池,没有多余开销

【memcache的细节讨论】

① 生命周期
从数据放入mem开始计时,直到时间到了,就销毁, 如果时间为0, 则表示不过期.

memcache的数据被销毁的情况如下:

  1. 时间到
  2. 重启memcached服务
  3. 重启memcached服务所在的机器
  4. delete / flush 销毁数据

② 如何把session数据放入到memcached服务中.

步骤:

  1. 修改php.ini的配置文件

如下:

;[sesson.save_handler有user|files|memcache]

session.save_handler= memcache

session.save_path= "tcp://127.0.0.1:11211"

③ 测试一把,重启apache

测试ok

<?php

//传统的代码

session_start();

$_SESSION['name']='天龙八部300';

$_SESSION['city']='beijing';

class Dog{

public $name;

}

$dog1=new Dog;

$dog1->name='abcde';

$_SESSION['dog']=$dog1;

//如果session数据入mem,那他一定是以session_id为

//key值进行添加

//取出

$name=$_SESSION['name'];

echo "name=$name";

echo "sessionid=".session_id();

思考,如果管理员,不让我们修改php.ini 文件,我们如何处理session入memcached这个功能, 我们通过一个函数可以去修改 php.ini 的配置.

代码:

<?php

ini_set("session.save_handler","memcache");

ini_set("session.save_path","tcp://127.0.0.1:9999");

同时你也可以通过 ini_set 去动态的修改对php.ini 的其它设置 。但是他不影响其它php页面,也不会去修改php.ini 文件本身, 只对本页面生效.

memcached vs session比较

memcached 主要的目的是提速 ,因此它是一种无状态的数据.即,数据不和用户绑定.
session数据是和用户绑定的,因此是一种有状态数据.

Memcached一些特性和限制

? 在 Memcached 中可以保存的item数据量是没有限制的,只有内存足够
? Memcached单进程最大使用内存为2G,要使用更多内存,可以分多个端口开启多个Memcached进程
? 最大30天的数据过期时间, 设置为永久的也会在这个时间过期,常量REALTIME_MAXDELTA
606024*30 控制
? 最大键长为250字节,大于该长度无法存储,常量KEY_MAX_LENGTH 250 控制
? 单个item最大数据是1MB,超过1MB数据不予存储,常量POWER_BLOCK 1048576 进行控制,
它是默认的slab大小
? 最大同时连接数是200,通过 conn_init()中的freetotal 进行控制,最大软连接数是1024,通过
settings.maxconns=1024 进行控制
? 跟空间占用相关的参数:settings.factor=1.25, settings.chunk_size=48, 影响slab的数据占用和步进方式

什么样的数据适合放入memcached中?

1)变化频繁,具有不稳定性的数据,不需要实时入库,如在线用户,session信息

2)和memcached技术类似是redis (key/value数据库),也是把数据放在内存中,并定时向磁盘同步

memcached的基本命令(安装、卸载、启动、配置相关):
-p 监听的端口
-l 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u 以的身份运行 (仅在以root运行的时候有效)
-m 最大内存使用,单位MB。默认64MB

-M 内存耗尽时返回错误,而不是删除项
-c 最大同时连接数,默认是1024
-f 块大小增长因子,默认是1.25
-n 最小分配空间,key+value+flags默认是48
-h 显示帮助

memcached的基本命令(当memcached 启动后 用于对memcached管理的数据和本身运行状态相关的命令):

Command
Description
Example

get
Reads a value
get mykey

set
Set a key unconditionally
set mykey 0 60 5

add
Add a new key
add newkey 0 60 5

replace
Overwrite existing key
replace key 0 60 5

append
Append data to existing key
append key 0 60 15

prepend
Prepend data to existing key
prepend key 0 60 15

incr
Increments numerical key value by given number
incr mykey 2

decr
Decrements numerical key value by given number
decr mykey 5

delete
Deletes an existing key
delete mykey

flush_all
Invalidate specific items immediately
flush_all

Invalidate all items in n seconds
flush_all 900

stats
Prints general statistics
stats

Prints memory statistics
stats slabs

Prints memory statistics
stats malloc

Print higher level allocation statistics
stats items

stats detail

stats sizes

Resets statistics
stats reset

version
Prints server version.
version

verbosity
Increases log level
verbosity

quit
Terminate telnet session
quit

对查看的信息的关键字中英文对照表

pid
memcache服务器的进程ID

uptime
服务器已经运行的秒数

time
服务器当前的unix时间戳

version
memcache版本

pointer_size
当前操作系统的指针大小(32位系统一般是32bit)

rusage_user
进程的累计用户时间

rusage_system
进程的累计系统时间

curr_items
服务器当前存储的items数量

total_items
从服务器启动以后存储的items总数量

bytes
当前服务器存储items占用的字节数

curr_connections
当前打开着的连接数

total_connections
从服务器启动以后曾经打开过的连接数

connection_structures
服务器分配的连接构造数

cmd_get
get命令(获取)总请求次数

cmd_set
set命令(保存)总请求次数

get_hits
总命中次数

get_misses
总未命中次数

evictions
为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items)

bytes_read
总读取字节数(请求字节数)

bytes_written
总发送字节数(结果字节数)

limit_maxbytes
分配给memcache的内存大小(字节)

threads
当前线程数

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容