查看当前的memcache连接数:
#netstat -n | grep :11211 | wc -l
haim参数 memcached -d -m 1500 -u backup -p 13000 -c 2048 -P /usr/local/memcached/tmp/memcached.pid
--------------------------------- mem和内存
每台memcached服务器仅启动一个memcached进程。分配给memcached的内存为3GB,启动参数如下:
/usr/bin/memcached -p 11211 -u nobody -m 3000 -c 30720
由于使用了x86_64的操作系统,因此能分配2GB以上的内存。32位操作系统中,每个进程最多只能使用2GB内存。也曾经考虑过启动多个分配2GB以下内存的进程,但这样一台服务器上的TCP连接数就会成倍增加,管理上也变得复杂,所以mixi就统一使用了64位操作系统。
另外,虽然服务器的内存为4GB,却仅分配了3GB,是因为内存分配量超过这个值,就有可能导致内存交换(swap)。连载的第2次中前坂讲解过了memcached的内存存储“slab allocator”,当时说过,memcached启动时指定的内存分配量是memcached用于保存数据的量,没有包括“slab allocator”本身占用的内存、以及为了保存数据而设置的管理空间。因此,memcached进程的实际内存分配量要比指定的容量要大,这一点应当注意。
mixi保存在memcached中的数据大部分都比较小。这样,进程的大小要比指定的容量大很多。因此,我们反复改变内存分配量进行验证,确认了3GB的大小不会引发swap,这就是现在应用的数值。
memcached -d -m 1024 -u root -l 172.25.38.70 -p 12000 -c 4096 -P /tmp/memcached.pid 12000
-p 12000 端口
-m 1024 内存设置 1024
-c 4096 同时连接数
-----------------------------------
/usr/local/bin/memcached -d -m 512 -u root -l 192.168.12.203 -p 13001 -c 1024
-d选项是启动一个守护进程daemon ,
-m是分配给Memcache使用的内存数量,单位是MB,我这里是10MB,默认64MB
-M 内存耗尽时返回错误,而不是删除项
-f 块大小增长因子,默认是1.25
-n 最小分配空间,key+value+flags默认是48
-u是运行Memcache的用户,我这里是root,
-l是监听的服务器IP地址,如果有多个地址的话,我这里指定了服务器的IP地址192.168.12.201,
-p是设置Memcache监听的端口,我这里设置了13001,最好是1024以上的端口,
-c选项是最大运行的并发连接数,默认是1024,我这里设置了256,按照你服务器的负载量来设定,
-P是设置保存Memcache的pid文件,与-d选择同时使用 ,我这里是保存在 /tmp/memcached.pid,
还有一些参数具体请参考:# /usr/local/bin/memcached -h
如果要结束Memcache进程,执行:kill `cat /tmp/memcached.pid`
----------memcache 替代session
/usr/local/bin/memcached -d -m 10 -u root -l 10.0.8.89 -p 13001 -c 512 -P /tmp/memcached13001.pid
原始
session.save_handler = files
mem:
session.save_handler = memcache
session.save_path = "tcp://192.168.0.26:13001,tcp://192.168.0.26:13002"
----------------------------------------consistent hash
在Memcache的实际使用中,遇到的最严重的问题,就是在增减服务器的时候,会导致大范围的缓存丢失,从而可能会引导数据库的性能瓶颈,为了避免出现这种情况,请先看Consistent hashing算法,中文的介绍可以参考这里,通过存取时选定服务器算法的改变,来实现。
修改PHP的Memcache扩展memcache.c的源代码中的
“memcache.hash_strategy” = standard
为
“memcache.hash_strategy” = consistent
重新编译,这时候就是使用Consistent hashing算法来寻找服务器存取数据了。
有效测试数据表明,使用Consistent hashing可以极大的改善增删Memcache时缓存大范围丢失的情况。
NonConsistentHash: 92% of lookups changed after adding a target to the existing 10
NonConsistentHash: 90% of lookups changed after removing 1 of 10 targets
ConsistentHash: 6% of lookups changed after adding a target to the existing 10
ConsistentHash: 9% of lookups changed after removing 1 of 10 targets
------------------------------ php 测试
<?php
$mem = new Memcache;
$mem->connect("192.168.1.252", 12000);
for($i=0;$i<1000000;$i++)
{
//$mem->set('key'.$i, 'This is a memcached test!', 0, 60);
//$val = $mem->get('key');
//echo $val;
$mem->delete('key'.$i);
}
?>
---------------------------------使用memcache情况,计数器、数据压缩
使用情况一:统计
<?php
//访问统计
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
if($s=$memcache->get('a')) {
$s=$s+1;
$memcache->set('a',$s);
}
else
$memcache->set('a',1);
echo '访问结果为:'.$s;
?>
其实我们可以用increment方法代替上面的做法
<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
if($s=$memcache->increment('a',1)) {
echo $s;
}
else
$memcache->set('a',1);
?>
数据压缩:
<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
$test=(str_repeat('jetwong',100000));
$memcache->set('b',($test));
?>
使用压缩:
<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
$test=(str_repeat('jetwong',100000));
$memcache->set('b',($test),MEMCACHE_COMdivSSED);
?>
使用情况说明:
前台比较
目前内存
bytes
总共读取
bytes_read
总共写入
bytes_written
压缩前
700085
700081
416
压缩后
1131
1125
13
可能看到压缩后明显占用内存少了不少
---------------------------Memcache内存的更新清理(delete flush)
<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
/*设置值*/
$status = $memcache->getStats();
echo '设置前内存使用情况'.$status['bytes'].'<br>';
echo '设置后';
for($i=0;$i<9;$i++) {
$memcache->set('b'.$i,rand(1,99));
echo '<br>'.$i.'->'.$memcache->get('b'.$i);
}
/*查看设置的值*/
$status = $memcache->getStats();
echo 'delete前内存使用情况'.$status['bytes'].'<br>';
echo '<br>开始delete';
for($i=0;$i<9;$i++) {
$memcache->delete('b'.$i);
echo '<br>'.$i.'->'.$memcache->get('b'.$i);
}
/*查看flush使用的情况*/
$status = $memcache->getStats();
echo '使用flush前内存使用情况'.$status['bytes'].'<br>';
echo '使用flush情况:';
for($i=0;$i<9;$i++) {
$memcache->set('b'.$i,rand(1,99));
echo '<br>'.$i.'->'.$memcache->get('b'.$i);
}
$memcache->flush();
echo 'flush之后:';
for($i=0;$i<9;$i++) {
echo '<br>'.$i.'->'.$memcache->get('b'.$i);
}
$status = $memcache->getStats();
echo 'flush后内存使用情况'.$status['bytes'].'<br>';
?>
-----------------------内存超量的测试(set)
我们把内存设为2M
./memcached -d -m 2 -p 11211 -u root
<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
//600K左右
$test1= str_repeat('jetlee',100000);
//600K左右
$test2= str_repeat('jetlee',100000);
//600K左右
$test3= str_repeat('李连杰',200000);
//600K左右
$test4= str_repeat('连杰李',100000);
//200K
$test5= file_get_contents('http://img.pconline.com.cn/images/photoblog/2988177/20068/4/1154688770042_mthumb.JPG');
$test6= file_get_contents('http://img.pconline.com.cn/images/photoblog/1767557/20069/28/1159417108902_mthumb.jpg');
for($i=1;$i<=6;$i++) {
$j='test'.$i;
if($memcache->set($j,$$j)) {
echo $j.'->设置成功<br>';
$status = $memcache->getStats();
echo '内存:'.$status['bytes'].'<br>';
}
else {
echo $j.'->设置失败<br>';
}
}
?>
执行结果:
test1->设置成功
内存:600042
test2->设置成功
内存:1200084
test3->设置失败
test4->设置成功
内存:1200084
test5->设置失败
test6->设置失败
刚好印证我们的计算,不过20万的repeat为什么会失败,不是太了解,,,,,,
总结:
示例:
<?
//设置篇
if($data = $memcache->get('k',$v)) {
//显示我们的数据
}
else {
$data = get_from_database; //得到数据源
if(!$memcache->set('k',$data), MEMCACHE_COMdivSSED) //开始设置
log(); //不成功,记录失败信息
}
?>
---------------------------memcached_check.sh 监控端口自动拉起
#!/bin/sh
#check memcache process and restart if down
#create by zhengdongliang
#path /data/sh/memcached/memcached_check.sh
#crontab time */10 * * * *
mm_bin="/usr/local/bin/memcached"
mm_log="/data/sh/memcached/memcached_check.log"
mm_ports=("13001" "13002" "13003" "13004")
mm_param=("-d -m 512 -p 13001 -u root" "-d -m 512 -p 13002 -u root" "-d -m 512 -p 13003 -u root" "-d -m 512 -p 13004 -u root")
mm_count=${#mm_ports[@]}
t=$(date -d "today" +"%Y-%m-%d %H:%M:%S")
i=0
while [ $i -lt $mm_count ]
do
mm_exists=`ps -ef|grep "memcached"|grep "${mm_ports[$i]}"|grep -v grep|wc -l`
if [ "$mm_exists" == "0" ]; then
${mm_bin} ${mm_param[$i]} 2>&1 > /dev/null &
echo "${t} : ${mm_bin} ${mm_param[$i]}" >> ${mm_log}
fi
let i++
done
===============================================================
添加为自动执行:
#crontab -e
*/10 * * * * /bin/sh /data/sh/memcached/memcached_check.sh >/dev/null 2>&1
系统每10分钟会自动执行memcached_check.sh
------------------------------------------适用于
用户信息seesion【hash(用户ID)】
分类及产品,最热贴,最新贴select sql语句【hash(sql),并实时更新】
------------------------------------------理解
MEMCACHE一个不足就是一重启服务器,数据将会丢失!
为什么会有Memcache和memcached两种名称?
其实Memcache是这个项目的名称,而memcached是它服务器端的主程序文件名,知道我的意思了把~~~~。一个是项目名称,一个是主程序文件名
,在网上看到了很多人不明白,于是混用了
.Web Server(Lighttpd、Nginx据说都比Apache效率高好多,大家可以试用下)对CPU要求高,对内存要求低;而Memcached Server是对CPU要
求低,对内存要求高,所以可以搭配使用。在对前端的Web Server上安装Memcached Server是可行的。
我考虑的一种简单方法:
后端的数据库操作模块,把所有的Select操作提取出来(update/delete/insert不管),然后把对应的SQL进行相应的hash算法计算得出一个
hash数据key(比如MD5或者SHA),然后把这个key去Memcache中查找数据,如果这个数据不存在,说明还没写入到缓存中,那么从数据库把数
据提取出来,一个是数组类格式,然后把数据在set到Memcache中,key就是这个SQL的hash值,然后相应的设置一个失效时间,比如一个小时,
那么一个小时中的数据都是从缓存中提取的,有效减少数据库的压力。缺点是数据不实时,当数据做了修改以后,无法实时到前端显示,并且
还有可能对内存占用比较大,毕竟每次select出来的数据数量可能比较巨大,这个是需要考虑的因素。
内网访问
最好把两台服务器之间的访问是内网形态的,一般是Web服务器跟Memcache服务器之间。普遍的服务器都是有两块网卡,一块指向互联网,一块
指向内网,那么就让Web服务器通过内网的网卡来访问Memcache服务器,我们Memcache的服务器上启动的时候就监听内网的IP地址和端口,内网
间的访问能够有效阻止其他非法的访问。
------------------------------------------ php 中memcache方法
直接 在php中 可以直接new 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("127.0.0.1", 11211);
$mem->set('key', 'This is a memcached test!', 0, 60);
$val = $mem->get('key');
echo $val;
<?php
$memcache_obj = new Memcache;
$memcache_obj->addServer('memcache_host', 11211);
$memcache_obj->addServer('failed_host', 11211);
$stats = $memcache_obj->getExtendedStats();
print_r($stats);
?>
$memcached = array( //用memcached 的 多 进程模拟 多台memcached 服务器 cn en 为 内存服务器名
'cn'=>array('192.168.254.144',11211),
'en'=>array('192.168.254.144',11212)
);
$sq = new Mysql;
$sql = "insert into mybb(pid) values(200)";
$mdsql = md5($sql);
if(!$result=$mem->get('cn_'.$mdsql)){
$sq->mquery("insert into mybb(pid) values(200)"); //插入到主mysql
$result = $sq->fetArray("select * from mybb"); //查询 是 从mysql
foreach($result as $var){
echo $var['pid'];
}
$mem->set('cn_'.$mdsql,$result); //添加到 名为 cn 的 memcached 服务器
}else{
foreach($result as $var){
echo $var['pid'];
}
}
------------------------------------------详细说明 http://www.ccvita.com/259.html
PHP的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 ."<br />";
//替换数据
$mem->replace('key1', 'This is replace value', 0, 60);
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "<br />";
//保存数组
$arr = array('aaa', 'bbb', 'ccc', 'ddd');
$mem->set('key2', $arr, 0, 60);
$val2 = $mem->get('key2');
echo "Get key2 value: ";
print_r($val2);
echo "<br />";
//删除数据
$mem->delete('key1');
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "<br />";
//清除所有数据
$mem->flush();
$val2 = $mem->get('key2');
echo "Get key2 value: ";
print_r($val2);
echo "<br />";
//关闭连接
$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 . "<br>";
最后我们把所有的保存在Memcache服务器上的数据都清除,会发现数据都没有了,最后输出key2的数据为空,最后关闭连接
$mem->flush();
$val2 = $mem->get(‘key2′);
echo "Get key2 value: ";
print_r($val2);
echo "<br>";
------------------------------------------推荐网址
http://www.ibm.com/developerworks/cn/opensource/os-php-fastapps3/
http://tech.idv2.com/2008/07/10/memcached-001/ 推荐mixi株式会社
http://bbs.phpchina.com/viewthread.php?tid=120151&highlight=memcache
http://bbs.phpchina.com/viewthread.php?tid=122462&highlight=memcache 基于Memcache的 Session数据的多服务器共享
http://bbs.phpchina.com/viewthread.php?tid=114865&highlight= 用memcache,文件操作代替数据库进行及时统计