乐趣区

关于php:php开发memcached

一、memcached 简介

memcached 是高性能的分布式内存缓存服务器。个别的应用目标是,通过缓存数据库查问后果,缩小数据库拜访次数,以进步动静 Web 利用的速度、进步可扩大

性。它能够应答任意多个连贯,应用非阻塞的网络 IO。因为它的工作机制是在内存中开拓一块空间,而后建设一个 HashTable,Memcached 自治理这些 HashTable。

二、memcached 装置(参考”Linux 下的 Memcache 装置”)

首先是下载 memcached 了,目前最新版本是 1.4.0,间接从官方网站即可下载到 memcached-1[1].4.0.tar.gz。除此之外,memcached 用到了 libevent,我 yum install libevent libevent-devel

接下来是将 memcached-1[1].4.0.tar.gz 解开包、编译、装置:

tar -xzf memcached-1.1.12.tar.gz

cd memcached-1.1.12

./configure

make

make install

三、运行 memcached 守护程序

运行 memcached 守护程序很简略,只需一个命令行即可,不须要批改任何配置文件(也没有配置文件给你批改):

/usr/local/bin/memcached -d -m 128 -l 192.168.x.y -p 11211 -u www

参数解释:

-d 以守护程序(daemon)形式运行 memcached;

-m 设置 memcached 能够应用的内存大小,单位为 M;

-l 设置监听的 IP 地址,如果是本机的话,通常能够不设置此参数;(个别是不写)

-p 设置监听的端口,默认为 11211,所以也能够不设置此参数;

-u 指定用户,如果以后为 root 的话,须要应用此参数指定用户。

当然,还有其它参数能够用,man memcached 一下就能够看到了。

四、memcached 的工作原理

首先 memcached 是以守护程序形式运行于一个或多个服务器中,随时承受客户端的连贯操作,客户端能够由各种语言编写,目前已知的客户端 API 包含 Perl/PHP/Python/Ruby/Java/C#/C 等等。PHP 等客户端在与 memcached 服务建设连贯之后,接下来的事件就是存取对象了,每个被存取的对象都有一个惟一的标识符 key,存取操作均通过这个 key 进行,保留到 memcached 中的对象实际上是搁置内存中的,并不是保留在 cache 文件中的,这也是为什么 memcached 可能如此高效疾速的起因。留神,这些对象并不是长久的,服务进行之后,里边的数据就会失落。

五、PHP 如何作为 memcached 客户端

有两种办法能够使 PHP 作为 memcached 客户端,调用 memcached 的服务进行对象存取操作。

第一种,PHP 有一个叫做 memcache 的扩大,Linux 下需编译装置 memcache,Window 下则在 php.ini 中去掉 php_memcache.dll 前边的正文符,使其可用。

参考张宴文章中装置 nginx 的一部分

编译装置 PHP5 扩大模块

tar zxvf memcache-2.2.5.tgz <—- 下载 (这是一个 php 扩大包资源库)
cd memcache-2.2.5/
/usr/local/webserver/php/bin/phpize
./configure –with-php-config=/usr/local/webserver/php/bin/php-config
make
make install
cd ../

这样,php.ini 文件中增加了 extension = “memcache.so”

例子(PHP 的 Memcache):

(1)

<?php

$mem = new Memcache;

$mem->connect(“192.168.x.y”, 11211)or die (“Could not connect”);

$mem->set(‘key’, ‘This is a test!’, 0, 60);

$val = $mem->get(‘key’);

echo $val;

?>

(2)

< ?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 的对象:
$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 的数据为空,最初敞开连贯

(3)数据

  
uid     username   password                         gender
751490 a62986233 8d03f56ad2c48d494cd4b73b3ba64dca       0
751489 hldhoxbh   25d55ad283aa400af464c76d713c07ad       0
751488 wuhan0088 ba2206cbae7c1bfe33a54ff161943bab       0
751487 anrron     b206e95a4384298962649e58dc7b39d4       0
751486 hldjxlkx   9c98df872d24244696c393a1d26ab749       0
751485 1394afjh   25d55ad283aa400af464c76d713c07ad       0
751484 yesi808   32baeaa3c422413843b015919c0be999       0
751483 IDC010pw   25f9e794323b453885f5181f1b624d0b       0
751482 ebay360v   a36b9e764318d31b4810d7d18096e6e7       0
751481 ppgqsvgv   9c98df872d24244696c393a1d26ab749       0

10 rows in set (0.00 sec)

<?php

# 数据库连贯信息

$host=”192.168.0.71″;

$user=”askwan”;

$passwd=”passwd”;

$db=”pwbbs”;

$query=”select UID,username,password,gender from pw_members order by uid desc limit 10;”

# 我这里选用了 MD5 形式加密 SQL 做为 key,也可用其余加密形式,如 Base64 等

$m_key=md5($query);

$mem=new Memcache();

$mem->connect(“192.168.0.72”,11211);

if(!$result=$mem->get($m_key)){

echo “ 这是从数据库读出来的后果!”;

$connection=mysql_connect($host,$user,$passwd) or die (“Unable to conect!”);

mysql_select_db($db);

$result=mysql_query($query) or die(“Error query!”.mysql_error());

while($row=mysql_fetch_row($result)){

$memdata[]=$row;

}

$mem->add($m_key,$memdata);

mysql_free_result($result);

mysql_close($connection);

}

else{

echo “ 这是从 Memcached Server 读出来的后果!n”;

}

$result=$mem->get($m_key);

# 显示获取的数据

echo “<table cellpadding=10 border=2>”;

echo “<tr>”;

echo “<th>Uid</th>”;

echo “<th>Username</th>”;

echo “<th>PassWord</th>”;

echo “<th>Gender</th>”;

echo “</tr>”;

for($i=0;$i<10;$i++){

echo “<tr>”;

for($j=0;$j<4;$j++){

echo “<td>”.$result[$i][$j].”</td>”;

}

echo “</tr>”;

}

?>

第二种,能够避开扩大、从新编译所带来的麻烦,那就是间接应用 php-memcached-client.php, 但效率会比扩大库稍差一些。

首先 下载 memcached-client.php,在下载了 memcached-client.php 之后,就能够通过这个文件中的类“memcached”对 memcached 服务进行操作了。其实代码调用非常简单,次要会用到的办法有 add()、get()、replace() 和 delete(),办法阐明如下:

add ($key, $val, $exp = 0)
往 memcached 中写入对象,$key 是对象的惟一标识符,$val 是写入的对象数据,$exp 为过期工夫,单位为秒,默认为不限工夫;

get ($key)
从 memcached 中获取对象数据,通过对象的惟一标识符 $key 获取;

replace ($key, $value, $exp=0)
应用 $value 替换 memcached 中标识符为 $key 的对象内容,参数与 add() 办法一样,只有 $key 对象存在的状况下才会起作用;

delete ($key, $time = 0)
删除 memcached 中标识符为 $key 的对象,$time 为可选参数,示意删除之前须要期待多长时间。

上面是一段简略的测试代码,代码中对标识符为 ‘mykey’ 的对象数据进行存取操作:

<?php

// 蕴含 memcached 类文件

require_once(‘memcached-client.php’);

// 选项设置

$options = array(

‘servers’ => array(‘192.168.10.215:11211’), //memcached 服务的地址、端口,可用多个数组元素示意多个 memcached 服务

‘debug’ => false,  // 是否关上 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 “
“.str_pad(‘$mc->add() ‘, 60, ‘_’).”
“;

var_dump($val);

// 替换已写入的对象数据值

$mc->replace($key, array(‘some’=>’haha’, ‘array’=>’xxx’));

$val = $mc->get($key);

echo “
“.str_pad(‘$mc->replace() ‘, 60, ‘_’).”
“;

var_dump($val);

// 删除 memcached 中的对象

$mc->delete($key);

$val = $mc->get($key);

echo “
“.str_pad(‘$mc->delete() ‘, 60, ‘_’).”
“;

var_dump($val);

?>

是不是很简略,在理论利用中,通常会把数据库查问的后果集保留到 memcached 中,下次访问时间接从 memcached 中获取,而不再做数据库查问操作,这样能够在很大水平上加重数据库的累赘。通常会将 SQL 语句 md5() 之后的值作为惟一标识符 key。下边是一个利用 memcached 来缓存数据库查问后果集的示例(此代码片段紧接上边的示例代码):

<?php

$sql = ‘SELECT * FROM users’;

$key = md5($sql);   //memcached 对象标识符

if (!($datas = $mc->get($key)) ) {

// 在 memcached 中未获取到缓存数据,则应用数据库查问获取记录集。

echo “
“.str_pad(‘Read datas from MySQL.’, 60, ‘_’).”
“;

$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 “
“.str_pad(‘Read datas from memcached.’, 60, ‘
‘).”n”;

}

var_dump($datas);

?>

能够看出,应用 memcached 之后,能够缩小数据库连贯、查问操作,数据库负载下来了,脚本的运行速度也进步了。

Memcache的应用
应用 Memcache 的网站个别流量都是比拟大的,为了缓解数据库的压力,让 Memcache 作为一个缓存区域,把局部信息保留在内存中,在前端可能迅速 的进行存取。那么个别的焦点就是集中在如何分担数据库压力和进行分布式,毕竟单台 Memcache 的内存容量的无限的。我这里简略提出我的集体认识,未经 实际,权当参考。

分布式应用
Memcache 原本反对分布式,咱们客户端稍加革新,更好的反对。咱们的 key 能够适当进行有法则的封装,比方以 user 为主的网站来说,每个用户都有 User ID,那么能够依照固定的 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 服务器的拜访,可能无效的阻止一些非法拜访,相应的也能够减少一些其余的规定来增强安全性,这个能够依据本人的须要来做。

参考(1)

Linux 下的 Memcache 装置

最近在钻研怎么让 Discuz! 去利用 Memcache 去做一些事件,记录下 Memcache 装置的过程。

Linux下 Memcache 服务器端的装置
服务器端次要是装置 memcache 服务器端,目前的最新版本是 memcached-1.3.0。
1.2.2.tar.gz
另外,Memcache 用到了 libevent 这个库用于 Socket 的解决,所以还须要装置 libevent,libevent 的最新版本是 libevent-1.3。(如果你的零碎曾经装置了 libevent,能够不必装置)
用 wget 指令间接下载这两个货色. 下载回源文件后。
1. 先装置 libevent。这个货色在配置时须要指定一个装置门路,即./configure –prefix=/usr;而后 make;而后 make install;
2. 再装置 memcached,只是须要在配置时须要指定 libevent 的装置门路即./configure –with-libevent=/usr;而后 make;而后 make install;
这样就实现了 Linux 下 Memcache 服务器端的装置。具体的办法如下:

1. 别离把 memcached 和 libevent 下载回来,放到 /tmp 目录下:
cd /tmp
1.2.0.tar.gz

2. 先装置 libevent:
tar zxvf libevent-1.2.tar.gz
cd libevent-1.2
./configure –prefix=/usr
make
make install

3. 测试 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
还不错,都装置上了。

4. 装置 memcached,同时须要装置中指定 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,

5. 测试是否胜利装置 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 的 PHP 扩大
1. 抉择相应想要下载的 memcache 版本。
2. 装置 PHP 的 memcache 扩大

tar vxzf memcache-2.2.1.tgz
cd memcache-2.2.1
/usr/local/php/bin/phpize
./configure –enable-memcache –with-php-config=/usr/local/php/bin/php-config –with-zlib-dir
make
make install

3. 上述装置完后会有相似这样的提醒:

Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-2007xxxx/

4. 把 php.ini 中的 extension_dir =“./”批改为

extension_dir =“/usr/local/php/lib/php/extensions/no-debug-non-zts-2007xxxx/”

5. 增加一行来载入 memcache 扩大:extension=memcache.so

memcached的根本设置
1. 启动 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,

2. 如果要完结 Memcache 过程,执行:

kill cat /tmp/memcached.pid

也能够启动多个守护过程,不过端口不能反复。

3. 重启 apache,service httpd restart

Memcache环境测试
运行上面的 php 文件,如果有输入 This is a test!,就示意环境搭建胜利。开始领略 Memcache 的魅力把!
< ?php
$mem = new Memcache;
$mem->connect(”127.0.0.1″, 11211);
$mem->set(’key’,‘This is a test!’, 0, 60);
$val = $mem->get(’key’);
echo $val;
?>

退出移动版