<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[BIWEB开源PHP WMS系统创始人ArthurXF肖飞的blog]]></title> 
<link>http://www.bizeway.net/index.php</link> 
<description><![CDATA[网务通 - 网务公司发展之路]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[BIWEB开源PHP WMS系统创始人ArthurXF肖飞的blog]]></copyright>
<item>
<link>http://www.bizeway.net/read.php?</link>
<title><![CDATA[跟ArthurXF探讨大型网站架构——资料篇2]]></title> 
<author>ArthurXF &lt;arthurxf@gmail.com&gt;</author>
<category><![CDATA[网站架构]]></category>
<pubDate>Sun, 12 Aug 2007 07:29:47 +0000</pubDate> 
<guid>http://www.bizeway.net/read.php?</guid> 
<description>
<![CDATA[ 
	　　上一篇我们看了分布式运算的资料，这次我们来看看分布式内存共享。目前在ＰＨＰ领域中能够做到分布式内存共享的只有Memcache。<br/><br/>1.memcached详细介绍。<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">通常的网页缓存方式有动态缓存和静态缓存等几种，在ASP.NET中已经可以实现对页面局部进行缓存，而使用memcached的缓存比 ASP.NET的局部缓存更加灵活，可以缓存任意的对象，不管是否在页面上输出。而memcached最大的优点是可以分布式的部署，这对于大规模应用来 说也是必不可少的要求。<br/>LiveJournal.com使用了memcached在前端进行缓存，取得了良好的效果，而像wikipedia,sourceforge等也采用了或即将采用memcached作为缓存工具。memcached可以大规模网站应用发挥巨大的作用。<br/><br/>Memcached是什么?<br/>Memcached是高性能的，分布式的内存对象缓存系统，用于在动态应用中减少数据库负载，提升访问速度。<br/>Memcached由Danga Interactive开发，用于提升LiveJournal.com访问速度的。LJ每秒动态页面访问量几千次，用户700万。Memcached将数据库负载大幅度降低，更好的分配资源，更快速访问。<br/><br/>如何使用memcached-Server端?<br/>在服务端运行：<br/># ./memcached -d -m 2048 -l 10.0.0.40 -p 11211<br/>这将会启动一个占用2G内存的进程，并打开11211端口用于接收请求。由于32位系统只能处理4G内存的寻址，所以在大于4G内存使用PAE的32位服务器上可以运行2-3个进程，并在不同端口进行监听。<br/><br/>如何使用memcached-Client端?<br/>在应用端包含一个用于描述Client的Class后，就可以直接使用，非常简单。<br/>PHP Example:<br/>$options["servers"] = array("192.168.1.41:11211", "192.168.1.42:11212");<br/>$options["debug"] = false;<br/>$memc = new MemCachedClient($options);<br/>$myarr = array("one","two", 3);<br/>$memc->set("key_one", $myarr);<br/>$val = $memc->get("key_one");<br/>print $val[0]."&#92;n"; // prints 'one‘<br/>print $val[1]."&#92;n"; // prints 'two‘<br/>print $val[2]."&#92;n"; // prints 3<br/><br/>为什么不使用数据库做这些？<br/><br/>暂且不考虑使用什么样的数据库(MS-SQL, Oracle, Postgres, MysQL-InnoDB, etc..), 实现事务(ACID，Atomicity, Consistency, Isolation, and Durability )需要大量开销，特别当使用到硬盘的时候，这就意味着查询可能会阻塞。当使用不包含事务的数据库（例如Mysql-MyISAM），上面的开销不存在，但 读线程又可能会被写线程阻塞。<br/>Memcached从不阻塞，速度非常快。<br/><br/>为什么不使用共享内存?<br/>最初的缓存做法是在线程内对对象进行缓存，但这样进程间就无法共享缓存，命中率非常低，导致缓存效率极低。后来出现了共享内存的缓存，多个进程或者线程共享同一块缓存，但毕竟还是只能局限在一台机器上，多台机器做相同的缓存同样是一种资源的浪费，而且命中率也比较低。<br/>Memcached Server和Clients共同工作，实现跨服务器分布式的全局的缓存。并且可以与Web Server共同工作，Web Server对CPU要求高，对内存要求低，Memcached Server对CPU要求低，对内存要求高，所以可以搭配使用。<br/><br/>Mysql 4.x的缓存怎么样?<br/>Mysql查询缓存不是很理想，因为以下几点：<br/>当指定的表发生更新后，查询缓存会被清空。在一个大负载的系统上这样的事情发生的非常频繁，导致查询缓存效率非常低，有的情况下甚至还不如不开，因为它对cache的管理还是会有开销。<br/>在32位机器上，Mysql对内存的操作还是被限制在4G以内，但memcached可以分布开，内存规模理论上不受限制。<br/>Mysql上的是查询缓存，而不是对象缓存，如果在查询后还需要大量其它操作，查询缓存就帮不上忙了。<br/>如果要缓存的数据不大，并且查询的不是非常频繁，这样的情况下可以用Mysql 查询缓存，不然的话memcached更好。<br/><br/>数据库同步怎么样？<br/>这里的数据库同步是指的类似Mysql Master-Slave模式的靠日志同步实现数据库同步的机制。<br/>你可以分布读操作，但无法分布写操作，但写操作的同步需要消耗大量的资源，而且这个开销是随着slave服务器的增长而不断增长的。<br/>下一步是要对数据库进行水平切分，从而让不同的数据分布到不同的数据库服务器组上，从而实现分布的读写，这需要在应用中实现根据不同的数据连接不同的数据库。<br/>当这一模式工作后（我们也推荐这样做），更多的数据库导致更多的让人头疼的硬件错误。<br/>Memcached可以有效的降低对数据库的访问，让数据库用主要的精力来做不频繁的写操作，而这是数据库自己控制的，很少会自己阻塞 自己。<br/><br/>Memcached快吗？<br/><br/>非常快，它使用libevent，可以应付任意数量打开的连接（使用epoll，而非poll），使用非阻塞网络IO，分布式散列对象到不同的服务器，查询复杂度是O(1)。(于敦德)<br/><br/>参考资料：<br/>Distributed Caching with Memcached &#124; Linux Journal<br/>http://www.danga.com/<br/>http://www.linuxjournal.com/article/7451</div></div><br/><br/>2.memcached在freebsd下的安装：<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">步骤1：安装memcached<br/>代码:<br/># cd /usr/ports/databases/memcached/<br/># make install<br/><br/>步骤2：启动memcached<br/>代码:<br/>#/usr/bin/memcached -d -m 128 -l 192.168.1.1 -p 11211 -u httpd<br/>参数解释：<br/>-d 以守护程序（daemon）方式运行 memcached；<br/>-m 设置 memcached 可以使用的内存大小，单位为 M；<br/>-l 设置监听的 IP 地址，如果是本机的话，通常可以不设置此参数；<br/>-p 设置监听的端口，默认为 11211，所以也可以不设置此参数；<br/>-u 指定用户，如果当前为 root 的话，需要使用此参数指定用户。<br/><br/>以上以完成了memcached的安装及启动!<br/>使用时按要求填上IP与端口既可</div></div><br/><br/>3.memcached 的工作原理<br/>首先 memcached 是以守护程序方式运行于一个或多个服务器中，随时接受客户端的连接操作，客户端可以由各种语言编写，目前已知的客户端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。PHP 等客户端在与 memcached 服务建立连接之后，接下来的事情就是存取对象了，每个被存取的对象都有一个唯一的标识符 key，存取操作均通过这个 key 进行，保存到 memcached 中的对象实际上是放置内存中的，并不是保存在 cache 文件中的，这也是为什么 memcached 能够如此高效快速的原因。注意，这些对象并不是持久的，服务停止之后，里边的数据就会丢失。<br/><a href="http://nio.infor96.com/wp-content/uploads/2006/11/image001.png" target="_blank"><img src="http://nio.infor96.com/wp-content/uploads/2006/11/image001.png" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0" align="left"/></a><br/><br/>4.安装php对memcache支持模块<br/>有两种方法可以使 PHP 作为 memcached 客户端，调用 memcached 的服务进行对象存取操作。<br/><br/>第一种，PHP 有一个叫做 memcache 的扩展，Linux 下编译时需要带上 –enable-memcache[=DIR] 选项，Window 下则在 php.ini 中去掉 php_memcache.dll 前边的注释符，使其可用。<br/><a href="http://pecl.php.net/package/memcache" target="_blank">http://pecl.php.net/package/memcache</a><br/><br/>除此之外，还有一种方法，可以避开扩展、重新编译所带来的麻烦，那就是直接使用 php-memcached-client。<br/><a href="http://nio.infor96.com/wp-content/uploads/2006/04/memcached-client.zip" target="_blank">http://nio.infor96.com/wp-content/uploads/2006/04/memcached-client.zip</a><br/>本文选用第二种方式，虽然效率会比扩展库稍差一些，但问题不大。<br/><br/>5.PHP memcached 应用示例<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">首先 下载 memcached-client.php，在下载了 memcached-client.php 之后，就可以通过这个文件中的类“memcached”对 memcached 服务进行操作了。其实代码调用非常简单，主要会用到的方法有 add()、get()、replace() 和 delete()，方法说明如下：<br/><br/>add ($key, $val, $exp = 0)<br/>往 memcached 中写入对象，$key 是对象的唯一标识符，$val 是写入的对象数据，$exp 为过期时间，单位为秒，默认为不限时间；<br/><br/>get ($key)<br/>从 memcached 中获取对象数据，通过对象的唯一标识符 $key 获取；<br/><br/>replace ($key, $value, $exp=0)<br/>使用 $value 替换 memcached 中标识符为 $key 的对象内容，参数与 add() 方法一样，只有 $key 对象存在的情况下才会起作用；<br/><br/>delete ($key, $time = 0)<br/>删除 memcached 中标识符为 $key 的对象，$time 为可选参数，表示删除之前需要等待多长时间。<br/><br/>下面是一段简单的测试代码，代码中对标识符为 'mykey' 的对象数据进行存取操作：<br/><br/><br/><pre><br/><?php<br/>// &nbsp; &nbsp;包含 memcached 类文件<br/>require_once('memcached-client.php');<br/>// &nbsp; &nbsp;选项设置<br/>$options = array(<br/> &nbsp; &nbsp;'servers' => array('192.168.1.1:11211'), //memcached 服务的地址、端口，可用多个数组元素表示多个 memcached 服务<br/> &nbsp; &nbsp;'debug' => true, &nbsp;//是否打开 debug<br/> &nbsp; &nbsp;'compress_threshold' => 10240, &nbsp;//超过多少字节的数据时进行压缩<br/> &nbsp; &nbsp;'persistant' => false &nbsp;//是否使用持久连接<br/> &nbsp; &nbsp;);<br/>// &nbsp; &nbsp;创建 memcached 对象实例<br/>$mc = new memcached($options);<br/>// &nbsp; &nbsp;设置此脚本使用的唯一标识符<br/>$key = 'mykey';<br/>// &nbsp; &nbsp;往 memcached 中写入对象<br/>$mc->add($key, 'some random strings');<br/>$val = $mc->get($key);<br/>echo "n".str_pad('$mc->add() ', 60, '_')."n";<br/>var_dump($val);<br/>// &nbsp; &nbsp;替换已写入的对象数据值<br/>$mc->replace($key, array('some'=>'haha', 'array'=>'xxx'));<br/>$val = $mc->get($key);<br/>echo "n".str_pad('$mc->replace() ', 60, '_')."n";<br/>var_dump($val);<br/>// &nbsp; &nbsp;删除 memcached 中的对象<br/>$mc->delete($key);<br/>$val = $mc->get($key);<br/>echo "n".str_pad('$mc->delete() ', 60, '_')."n";<br/>var_dump($val);<br/>?><br/></pre><br/><br/>是不是很简单，在实际应用中，通常会把数据库查询的结果集保存到 memcached 中，下次访问时直接从 memcached 中获取，而不再做数据库查询操作，这样可以在很大程度上减轻数据库的负担。通常会将 SQL 语句 md5() 之后的值作为唯一标识符 key。下边是一个利用 memcached 来缓存数据库查询结果集的示例（此代码片段紧接上边的示例代码）：<br/><br/><br/><?php<br/>$sql = 'SELECT * FROM users';<br/>$key = md5($sql); &nbsp; //memcached 对象标识符<br/>if ( !($datas = $mc->get($key)) ) {<br/> &nbsp; &nbsp;// &nbsp; &nbsp;在 memcached 中未获取到缓存数据，则使用数据库查询获取记录集。<br/> &nbsp; &nbsp;echo "n".str_pad('Read datas from MySQL.', 60, '_')."n";<br/> &nbsp; &nbsp;$conn = mysql_connect('localhost', 'test', 'test');<br/> &nbsp; &nbsp;mysql_select_db('test');<br/> &nbsp; &nbsp;$result = mysql_query($sql);<br/> &nbsp; &nbsp; &nbsp;while ($row = mysql_fetch_object($result))<br/> &nbsp; &nbsp; &nbsp; &nbsp;$datas[] = $row;<br/> &nbsp; &nbsp;// &nbsp; &nbsp;将数据库中获取到的结果集数据保存到 memcached 中，以供下次访问时使用。<br/> &nbsp; &nbsp;$mc->add($key, $datas);<br/>} else {<br/> &nbsp; &nbsp; &nbsp;echo "n".str_pad('Read datas from memcached.', 60, '_')."n";<br/>}<br/>var_dump($datas);<br/>?><br/><br/><br/>可以看出，使用 memcached 之后，可以减少数据库连接、查询操作，数据库负载下来了，脚本的运行速度也提高了。</div></div><br/><br/>6.使用memcache情况，计数器、数据压缩的例子<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>使用情况一：统计 <br/><?php<br/>//访问统计<br/>$memcache = new Memcache;<br/>$memcache->connect('localhost', 11211) or die ("Could not connect"); <br/>if($s=$memcache->get('a')) {<br/> &nbsp; &nbsp;$s=$s+1;<br/> &nbsp; &nbsp;$memcache->set('a',$s);<br/>}<br/>else<br/>$memcache->set('a',1);<br/>echo '访问结果为：'.$s;<br/>?><br/><br/>其实我们可以用increment方法代替上面的做法<br/><?php <br/>$memcache = new Memcache;<br/>$memcache->connect('localhost', 11211) or die ("Could not connect");<br/><br/>if($s=$memcache->increment('a',1)) {<br/> &nbsp; &nbsp;echo $s; &nbsp; &nbsp;<br/>}<br/>else<br/>$memcache->set('a',1);<br/>?><br/><br/> <br/><br/>数据压缩：<br/><?php<br/>$memcache = new Memcache;<br/>$memcache->connect('localhost', 11211) or die ("Could not connect"); <br/>$test=(str_repeat('jetwong',100000));<br/>$memcache->set('b',($test));<br/>?><br/>使用压缩：<br/><?php <br/>$memcache = new Memcache;<br/>$memcache->connect('localhost', 11211) or die ("Could not connect"); <br/>$test=(str_repeat('jetwong',100000));<br/>$memcache->set('b',($test),MEMCACHE_COMPRESSED);<br/>?><br/><br/><br/>使用情况说明：<br/><br/>前台比较 目前内存bytes 总共读取bytes_read 总共写入bytes_written<br/> <br/>压缩前 700085 700081 416<br/> <br/>压缩后 1131 1125 13<br/> <br/>可能看到压缩后明显占用内存少了不少<br/><br/> <br/><br/>Memcache内存的更新清理(delete flush)<br/><?php<br/>$memcache = new Memcache;<br/>$memcache->connect('localhost', 11211) or die ("Could not connect");<br/><br/>/*设置值*/<br/>$status = $memcache->getStats();<br/>echo '设置前内存使用情况'.$status['bytes'].'<br/>';<br/>echo '设置后';<br/>for($i=0;$i<9;$i++) {<br/> &nbsp; &nbsp;$memcache->set('b'.$i,rand(1,99)); &nbsp; &nbsp;<br/> &nbsp; &nbsp;echo '<br/>'.$i.'->'.$memcache->get('b'.$i); &nbsp; &nbsp; &nbsp; <br/>}<br/><br/>/*查看设置的值*/<br/>$status = $memcache->getStats();<br/>echo 'delete前内存使用情况'.$status['bytes'].'<br/>';<br/>echo '<br/>开始delete';<br/>for($i=0;$i<9;$i++) {<br/> &nbsp; &nbsp;$memcache->delete('b'.$i); &nbsp; &nbsp;<br/> &nbsp; &nbsp;echo '<br/>'.$i.'->'.$memcache->get('b'.$i);<br/>}<br/><br/>/*查看flush使用的情况*/<br/>$status = $memcache->getStats();<br/>echo '使用flush前内存使用情况'.$status['bytes'].'<br/>';<br/>echo '使用flush情况：';<br/>for($i=0;$i<9;$i++) {<br/> &nbsp; &nbsp;$memcache->set('b'.$i,rand(1,99)); &nbsp; &nbsp;<br/> &nbsp; &nbsp;echo '<br/>'.$i.'->'.$memcache->get('b'.$i); &nbsp;<br/>}<br/>$memcache->flush();<br/>echo 'flush之后：';<br/>for($i=0;$i<9;$i++) { &nbsp; &nbsp; &nbsp; &nbsp;<br/> &nbsp; &nbsp;echo '<br/>'.$i.'->'.$memcache->get('b'.$i);<br/>}<br/>$status = $memcache->getStats();<br/>echo 'flush后内存使用情况'.$status['bytes'].'<br/>';<br/>?><br/><br/>内存超量的测试(set)<br/><br/> 我们把内存设为2M<br/><br/>./memcached -d -m 2 -p 11211 -u root<br/><br/> <?php<br/>$memcache = new Memcache;<br/>$memcache->connect('localhost', 11211) or die ("Could not connect");<br/><br/>//600K左右<br/>$test1= str_repeat('jetlee',100000);<br/>//600K左右<br/>$test2= str_repeat('jetlee',100000);<br/>//600K左右<br/>$test3= str_repeat('李连杰',200000);<br/>//600K左右<br/>$test4= str_repeat('连杰李',100000);<br/>//200K<br/>$test5= file_get_contents('http://img.pconline.com.cn/images/photoblog/2988177/20068/4/1154688770042_mthumb.JPG');<br/>$test6= file_get_contents('http://img.pconline.com.cn/images/photoblog/1767557/20069/28/1159417108902_mthumb.jpg');<br/><br/>for($i=1;$i<=6;$i++) {<br/> &nbsp; &nbsp;$j='test'.$i;<br/> &nbsp; &nbsp;if($memcache->set($j,$$j)) {<br/> &nbsp; &nbsp; &nbsp; &nbsp;echo $j.'->设置成功<br/>';<br/> &nbsp; &nbsp; &nbsp; &nbsp;$status = $memcache->getStats();<br/> &nbsp; &nbsp; &nbsp; &nbsp;echo '内存:'.$status['bytes'].'<br/>';<br/> &nbsp; &nbsp;}<br/> &nbsp; &nbsp;else {<br/> &nbsp; &nbsp; &nbsp; &nbsp;echo $j.'->设置失败<br/>';<br/> &nbsp; &nbsp;}<br/>}<br/>?><br/><br/>执行结果：<br/><br/>test1->设置成功<br/>内存:600042<br/>test2->设置成功<br/>内存:1200084<br/>test3->设置失败<br/>test4->设置成功<br/>内存:1200084<br/>test5->设置失败<br/>test6->设置失败<br/><br/>刚好印证我们的计算，不过20万的repeat为什么会失败，不是太了解，，，，，，<br/><br/>总结：<br/>示例：<br/><?<br/>//设置篇<br/>if($data = $memcache->get('k',$v)) {<br/> &nbsp; &nbsp;//显示我们的数据<br/> &nbsp; &nbsp;}<br/>else {<br/> &nbsp; &nbsp;$data = get_from_database; //得到数据源<br/> &nbsp; &nbsp;if(!$memcache->set('k',$data), MEMCACHE_COMPRESSED) //开始设置<br/> &nbsp; &nbsp;log(); &nbsp; &nbsp;//不成功,记录失败信息 &nbsp; &nbsp;<br/>}<br/>?></div></div><br/><br/><br/>现在ArthurXF本人正在搞PHP等技术培训，如果想学习的人可以跟我联系。另外培训的招生简章在这个网址，想了解的可以去看看。加我QQ：29011218交流也可。<br/><a href="http://www.bizeway.net/read.php/285.htm" target="_blank">PHP培训招生简章</a><br/>Tags - <a href="tag.php?tag=memcache" rel="tag">memcache</a> , <a href="tag.php?tag=%E5%88%86%E5%B8%83%E5%BC%8F%E5%86%85%E5%AD%98%E5%85%B1%E4%BA%AB" rel="tag">分布式内存共享</a>
]]>
</description>
</item><item>
<link>http://www.bizeway.net/read.php?&amp;guid=0#topreply</link>
<title><![CDATA[[评论] 跟ArthurXF探讨大型网站架构——资料篇2]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.bizeway.net/read.php?&amp;guid=0#topreply</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>