smarty局部缓存

Smarty提供了强大的 缓存功能。但有时我们并不希望整篇文档都被缓存,而是有选择的缓存某一部分内容或某一部分内容不被缓存。例如你在页面上端使用一个带有广告条位置的模板, 广告条可以包含任何HTML、图象、FLASH等混合信息. 因此这里不能使用一个静态的链接,同时我们也不希望该广告条被缓存. 这就需要在 insert 函数指定,同时需要一个函数取广告条的内容信息。smarty也提供了这种缓存控制能力。

我们可以使用$smarty->register_block($params,&$smarty)使整篇页面中的某一块不被缓存。

index.tpl:

XML/HTML代码
  1. <div align='center'>
  2. Page created: {"0"|date_format:"%D %H:%M:%S"}
  3. <{dynamic}>
  4. Now is: {"0"|date_format:"%D %H:%M:%S"}
  5. ... do other stuff ...
  6. <{/dynamic}>
  7. </div>

index.php:

XML/HTML代码
  1. function smarty_block_dynamic($param, $content, &$smarty) {
  2. return $content;
  3. }
  4. $smarty = new Smarty;
  5. $smarty->caching = true;
  6. $smarty->register_block('dynamic', 'smarty_block_dynamic', false);
  7. if(!$smarty->is_cached()){
  8. .......
  9. }
  10. $smarty->display('index.tpl');

注解:
定义一个函数,函数名格式为:smarty_type_name($params, &$smarty)
type为block
name为用户自定义标签名称,在这里是{dynamic}
两个参数是必须的,即使在函数中没有使用也要写上。两个参数的功能同上。

单独这样使用,可能你发现并没有实现您所需要的功能,这是因为还需要在smarty_compiler.class.php中修改几行代码:

在上面的这个文件里面搜索$smarty->register_function('current_time','smarty_function_current_time',true);这个字符串,大约在702行。

把这行代码修改为:

if($tag_command == 'dynamic') $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, false);
else $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);

之后再打开您刚才写的页面就会发现部分缓存的功能已经实现了。

[教程]memcached for win32的安装

memcached是由livejournal团队(danga.com)制作的开源缓存软件,是缓存机制的一种实现,用它之所以高效,是因为它是利用了内存,使用好了能够大大加快页面或者是其它程序的执行速度。要注意的是一旦服务器停止,内存中的缓存数据会被清空。

win32下,需要启动memcached服务,首先下载相关的memcached文件(用于启动服务的windows.rar在附件中),解压后可以自己选择,这里我选择的是2.1版本的,将其中的memcached.exe和memcached.ini(里面也就这俩文件)拷贝到某路径下(如:E:\java\memcached2.1),然后通过cmd命令窗口,先转入到该路径,然后按如下步骤输入:

1、memcached.exe -d install

2、memcached.exe -d start

这里第一步是用于安装服务,第二步是用于启动服务,有些默认参数的值是通过memcached.ini里的相关元素的设置值而定的。

如果要停止服务和卸载服务可以用入下命令:

3、memcached.exe -d stop 或 memcached.exe -d shutdown

4、memcached.exe -d uninstall

命令参数解释:

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

-m 设置 memcached 可以使用的内存大小,单位为 M

-l 设置监听的 IP 地址,如果是本机的话,通常可以不设置此参数

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

-u 指定用户,如果当前为 root 的话,需要使用此参数指定用户
-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(增长因子:http://zhengjunwei2007-163-com.iteye.com/blog/963375)
-n 最小分配空间,key+value+flags默认是48
-h 显示帮助

memcached.ini文件指定的各参数及值可以根据需要做更改,默认的如下:

bind_addr=127.0.0.1
listener_port=11212
memory=16
max_conns=1024

evict_to_free = 0

说明:

bind_addr是指绑定的IP

listener_port是指监听的端口

memory内存大小

max_conns最大连接数

evict_to_free

在通过命令 memcached.exe -d start 将服务启动后,可以通过一个demo来做测试,这个demo的下载地址如下:

http://www.whalin.com/memcached/#download

运行类com.danga.MemCached.test.TestMemcached前将服务IP和监听端口改为启动服务时所用的IP和监听端口,

如:String[] servers = { "127.0.0.1:11212"};

或者可以用如下的Test类做测试

java 代码

 

  1. package com.danga.MemCached.test;       
  2.       
  3. import java.util.Date;       
  4.       
  5. import com.danga.MemCached.MemCachedClient;       
  6. import com.danga.MemCached.SockIOPool;       
  7.       
  8.       
  9. public class Test {           
  10.     protected static MemCachedClient mcc = new MemCachedClient();          
  11.           
  12.     static {          
  13.         String[] servers ={"127.0.0.1:11212"};          
  14.           
  15.         Integer[] weights = { 3 };          
  16.           
  17.         //创建一个实例对象SockIOPool        
  18.         SockIOPool pool = SockIOPool.getInstance();          
  19.           
  20.         // set the servers and the weights       
  21.         //设置Memcached Server       
  22.         pool.setServers( servers );          
  23.         pool.setWeights( weights );          
  24.           
  25.         // set some basic pool settings          
  26.         // 5 initial, 5 min, and 250 max conns          
  27.         // and set the max idle time for a conn          
  28.         // to 6 hours          
  29.         pool.setInitConn( 5 );          
  30.         pool.setMinConn( 5 );          
  31.         pool.setMaxConn( 250 );          
  32.         pool.setMaxIdle( 1000 * 60 * 60 * 6 );          
  33.           
  34.         // set the sleep for the maint thread          
  35.         // it will wake up every x seconds and          
  36.         // maintain the pool size          
  37.         pool.setMaintSleep( 30 );          
  38.           
  39. //        Tcp的规则就是在发送一个包之前,本地机器会等待远程主机       
  40. //        对上一次发送的包的确认信息到来;这个方法就可以关闭套接字的缓存,       
  41. //        以至这个包准备好了就发;       
  42.         pool.setNagle( false );          
  43.         //连接建立后对超时的控制       
  44.         pool.setSocketTO( 3000 );       
  45.         //连接建立时对超时的控制       
  46.         pool.setSocketConnectTO( 0 );          
  47.           
  48.         // initialize the connection pool          
  49.         //初始化一些值并与MemcachedServer段建立连接       
  50.         pool.initialize();       
  51.                   
  52.           
  53.         // lets set some compression on for the client          
  54.         // compress anything larger than 64k          
  55.         mcc.setCompressEnable( true );          
  56.         mcc.setCompressThreshold( 64 * 1024 );          
  57.     }          
  58.               
  59.     public static void bulidCache(){          
  60.         //set(key,value,Date) ,Date是一个过期时间,如果想让这个过期时间生效的话,这里传递的new Date(long date) 中参数date,需要是个大于或等于1000的值。       
  61.         //因为java client的实现源码里是这样实现的 expiry.getTime() / 1000 ,也就是说,如果 小于1000的值,除以1000以后都是0,即永不过期       
  62.         mcc.set( "test""This is a test String" ,new Date(10000));   //十秒后过期       
  63.                  
  64.     }          
  65.          
  66.     public static void output() {          
  67.         //从cache里取值       
  68.         String value = (String) mcc.get( "test" );          
  69.         System.out.println(value);           
  70.     }          
  71.               
  72.     public static void main(String[] args){          
  73.         bulidCache();         
  74.         output();              
  75.     }        
  76.           
  77. }  

 应用memcached的一个心得:

1、客户端在与 memcached 服务建立连接之后,进行存取对象的操作,每个被存取的对象都有一个唯一的标识符 key,存取操作均通过这个 key 进行,保存到 memcached 中的对象实际上是放置内存中的,并不是保存在 cache 文件中的,这也是为什么 memcached 能够如此高效快速的原因。注意,这些对象并不是持久的,服务停止之后,里边的数据就会丢失。

2、当存入cached的数据超过了cached的容量后会将最长时间没调用的对象挤出,这正好应征了cached的特征。

3、利用memcached常用的做法:在每取得一次cached对象后,重新设置这个对象的cache时间,这样能够使得经常被调用的对象可以长期滞留在缓存中,使得效率增倍。

windows.rar (2.5 MB)

相关教程:

Linux下Memcached的安装及配置:http://blog.haohtml.com/archives/364
基于 PHP5 & JQuery 的 Memcached 管理监控工具:http://www.junopen.com/memadmin/

[缓存加速]eAccelerator与memcached的区别与用途

eAccelerator和memcached,是目前较为主流的两个可使用在PHP之中的缓存加速工具.

eAccelerator专门为PHP开发,而memcached不仅仅用在PHP之中,其他所有的语言都可以使用.

eAccelerator的主要功能:
1. 缓存PHP文件的执行代码:在被缓存的代码再次被调用时,将直接从内存读取,从而在很大程度了PHP运行的速度.
2. 提供了共享内存操作函数:用户可以将自己的常见非资源对像,保存到内存之中,并可以随时读取出来.

memcached的主要功能:
提供共享内存操作函数,可以保存和读取数据

两者的共同点:
共同点:都提供了共享内存操作函数,可以用来保存和读取自己的数据

两者的区别
eAccelerator作为PHP的扩展库存在,那么仅在PHP运行时,可以操作和读写共享内存,一般情况,只能由操作共享内存的程序自己调用.同时,eAccelerator可以缓存PHP程序的执行代码,提升程序的调入和执行速度.
memcached主要作为一个共享内存服务器,其PHP扩展库仅仅作为PHP到memcached的连接库存在,类似MySQL扩展库.因而,memcached可以完全脱离PHP,其共享的数据,可以被不同的程序调用.

根据两者的不同,我们将他们使用在真真需要的地方:
eAccelerator主要用于单机PHP提速,缓存中间数据.对于实时性高,但数据操作量小的情况下,非常实用.
memcached用于分布式或者集群系统,多台服务器可以共享数据.对于实时性高,同时数据操作量大的情况下,非常实用.

memcached安装+php使用手记

http://blog.csdn.net/felio/archive/2006/09/29/1303647.aspx

本文简要介绍一下安装的情况,以及PHP模块memcache使用情况:

提要:
1。安装memcached服务器端
2。安装phpmemcache支持模块
3。使用memcache情况,计数器、数据压缩
4。Memcache内存的更新清理(delete flush)
5。内存超量的测试(set)

1。安装memcached服务器端
memcached
安装说明(北南南北的站)
http://www.linuxsir.org/main/?q=node/184 

Linux下缓存服务器的应用
作者:tonyvicky
来自:LinuxSir.Org
摘要:由于数据库存储的数据量越来越大,查询速度也就变的越来越慢,因此就有了缓存服务器应用的必要,本文是介绍Memcached的安装以及简单的使用。

本文只介绍memcached的PHP的API,想查看其他关于Memcached的API文档案,请访问 http:
//www.danga.com/memcached/

目录

一、环境需求
二、下载相关软件
三、安装和配置

1、安装Memcached
2、安装memcache PHP模块
3、测试脚本
四、关于本文


++++++++++++++++++++++++++++++++++++++++
正文
++++++++++++++++++++++++++++++++++++++++


一、环境需求
安装Memcached需要libevent库的支持,所以请在安装Memcached之前检查有没有安装libevent。测试环境还需要PHP的支持,本文假设PHP已经安装到
/usr/local/php目录下,也就是在编译PHP的时候使用perfix参数指定目录(--prefix=/usr/local/php)

二、下载相关软件

Memcached下载地址:http:
//www.danga.com/memcached/
memcache PHP模块下载地址: http:
//pecl.php.net/package/memcache 推荐使用1.5版
libevent 下载地址: http:
//www.monkey.org/~provos/libevent/

本文不再讲述如何安装libevent,可以参考:http://blog.haohtml.com/archives/364

三、安装和配置

1、安装Memcached


root@tonyvicky:
# tar vxzf memcached-1.1.12.tar.gz
root@tonyvicky:# cd memcached-1.1.12
root@tonyvicky:# ./configure --prefix=/usr/local/memcached
root@tonyvicky:# make
root@tonyvicky:# make install

安装完之后要启动服务


root@tonyvicky:
# cd /usr/local/memcached/bin
root@tonyvicky:# ./memcached -d -m 50 -p 11211 -u root

参数说明 
-m 指定使用多少兆的缓存空间;-p 指定要监听的端口; -u 指定以哪个用户来运行

2、安装memcache PHP模块


root@tonyvicky:
# tar vxzf memcache-1.5.tgz
root@tonyvicky:# cd memcache-1.5
root@tonyvicky:# /usr/local/php/bin/phpize
root@tonyvicky:# ./configure --enable-memcache --with-php-config=/usr/local/php/bin/php-config --with-zlib-dir
root@tonyvicky:# make
root@tonyvicky:# make install

安装完后会有类似这样的提示:


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

把这个记住,然后修改php.ini,把


extension_dir 
= "./"

修改为


extension_dir 
= "/usr/local/php/lib/php/extensions/no-debug-non-zts-20050922/"

并添加一行


extension
=memcache.so

3、测试脚本

自己写一个PHP程序测试一下吧


<?php
$memcache 
= new Memcache; //创建一个memcache对象
$memcache
->connect('localhost'11211or die ("Could not connect"); //连接Memcached服务器
$memcache
->set('key''test'); //设置一个变量到内存中,名称是key 值是test
$get_value 
= $memcache->get('key'); //从内存中取出key的值
echo $get_value;
?
>

注意的是:如果你安装过程中出现错误,请看看是不是有模块没装:
autoconf
zlib (
压缩数据用

)

2。安装phpmemcache支持模块
PHP
老家:
http://cn.php.net/manual/zh/ref.memcache.php

 

Memcache Functions
简介
Memcache module provides handy procedural and 
object oriented interface to memcached, highly effective caching daemon, which was especially designed to decrease database load in dynamic web applications.

This module doesn
't have native support of multiple servers, but you still can implement it yourself in your application. Establish several memcached connections, set priority level for each server etc.

More information about memcached can be found at http://www.danga.com/memcached/.

需求
This module uses functions of zlib to support on-the-fly data compression. Zlib is required to install this module.

PHP 4.3.3 or newer is required to use the memcache extension.

安装
本 PECL 扩展未绑定于 PHP 中。 进一步信息例如新版本,下载,源程序,维护者信息以及更新日志可以在此找到: http://pecl.php.net/package/memcache.

In order to use these functions you must compile PHP with Memcache support by using the --enable-memcache[=DIR] option.

Windows users will enable php_memcache.dll inside of php.ini in order to use these functions. 可以从 PHP 下载页面或者 http://snaps.php.net/ 下载此 PECL 扩展的 DLL 文件。

预定义常量
表格 1. MemCache Constants

Name Description
MEMCACHE_COMPRESSED (integer)  Used to turn on-the-fly data compression on with Memcache::set(), Memcache::add() 和 Memcache::replace().

运行时配置
本扩展模块在 php.ini 中未定义任何配置选项。

资源类型
There is only one resource type used in memcache module - it
's the link identifier for a cache server connection.

范例
例子 
1. memcache extension overview example

<?php

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

$version = $memcache->getVersion();
echo "Server's version: ".$version."<br/> ";

$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)<br/> ";

$get_result = $memcache->get('key');
echo "Data from the cache:<br/> ";

var_dump($get_result);

?>



In the above example
, an object is being saved in the cache and then retrieved back. Object and other non-scalar types are serialized before saving, so it's impossible to store resources (i.e. connection identifiers and others) in the cache.

目录
Memcache::add -- Add an item to the server
Memcache::close -- Close memcached server connection
Memcache::connect -- Open memcached server connection
memcache_debug -- Turn debug output on/off
Memcache::decrement -- Decrement item
's value
Memcache
::delete -- Delete item from the server
Memcache
::flush -- Flush all existing items at the server
Memcache
::get -- Retrieve item from the server
Memcache
::getStats -- Get statistics of the server
Memcache
::getVersion -- Return version of the server
Memcache
::increment -- Increment item's value
Memcache::pconnect -- Open memcached server persistent connection
Memcache::replace -- Replace value of the existing item
Memcache::set -- Store data at the server



 add a note User Contributed Notes
Memcache Functions
ed at me3inc dot com
27-Oct-2006 05:47
Re. Installing the memcache extension:

I had all kinds of troubles getting it hooked up, because in all of the instructions I read I never got the last, most important step - you must have a php.ini and have in it "extension=memcache.so."

So, the steps:
First - ./configure with --enable-memcache. This should show in your phpinfo() at the top (even though nothing of the memcache extension works yet).

Second:
either pecl install memcache
OR
download the source
tar -xzvf [thesourcetarball]
phpize
./configure
make
make install

Finally: Add extension=memcache.so to your php.ini. (If you don
't have one, it should go in the root of where php is called ie., /usr/local/lib)

Call 
phpinfo() and you should see a memcache section.
iliya at pisem dot net
20-Jan-2006 04:35
one more 
"intelligent" cache aggregator:
https
://svn.shadanakar.org/onPHP/ trunk/core/Cache/AggregateCache.class.php
can be used with several cache connectors - memcached, filesystem, etc.
(remove whitespace manually)
Gregor J
. Rothfuss
22-Nov-2005 01:18
The 
next version will have failover. It's been committed three weeks ago. Usage notes here: http://www.codecomments.com/archive367-2005-10-659421.html
Ron
15-Sep-2005 04:19
An improvement to the above:

The above class will cause an error if all cache servers are down.  The preferred behavior is to just have a cache miss (or take no action in the case of write operations) and return false, so the app can run in non-cached mode if all cache servers are down.

To make this happen, simply change the connection usage to look something like this in each affected function.  This code is for the get() function:

       $con = $this->_getConForKey($key);
       if ($con === false) return false;
       return $con->get($key);

Similarly, the affected code in the set() function would look like this:
   $con = $this->_getConForKey($key);
   if ($con === false) return false;
   return $con->set($key, $var, $compress, $expire);

Modify each function accordingly, and if all of your cache servers are down, you can still function (although more slowly due to the 100% cache miss rate).
Ron
15-Sep-2005 01:20
Here is a simple memcached aggregator class which distributes the cache among multiple cache servers.  If a server fails, the load is redistributed automatically.  It uses persistent connections.

The constructor takes an array of arrays, with each inner array representing a server, with a 
'server' (string) attribute that is the IP addres or host name of the memcached server, and a 'port' (int) attribute that is the port number on which memcached is running on the server.

All of the existing memcached API functions are implemented except getStats() and getVersion(), which are server-specific.

<?php
class MemcachedAggregator {
   var $connections;

   public function __construct($servers) {
   // Attempt to establish/retrieve persistent connections to all servers.
   // If any of them fail, they just don
't get put into our list of active
   
// connections.
   $this->connections = array();
   
for ($i = 0, $n = count($servers); $i < $n$i++) {
       
$server = $servers[$i];
       
$con = memcache_pconnect($server['host'], $server['port']);
       
if (!($con == false)) {
       
$this->connections[] = $con;
       }
   }
   }

   
private function _getConForKey($key) {
   
$hashCode = 0;
   
for ($i = 0, $len = strlen($key); $i < $len$i++) {
       
$hashCode = (int)(($hashCode*33)+ord($key[$i])) & 0x7fffffff;
   }
   
if (($ns = count($this->connections)) > 0) {
       
return $this->connections[$hashCode%$ns];
   }
   
return false;
   }

   
public function debug($on_off) {
   
$result = false;
   
for ($i = 0$i < count($connections); $i++) {
       
if ($this->connections[$i]->debug($on_off)) $result = true;
   }
   
return $result;
   }

   
public function flush() {
   
$result = false;
   
for ($i = 0$i < count($connections); $i++) {
       
if ($this->connections[$i]->flush()) $result = true;
   }
   
return $result;
   }

/// The following are not implemented:
//
/getStats()
//
/getVersion()

   
public function get($key) {
   
if (is_array($key)) {
       
$dest = array();
       
foreach ($key as $subkey) {
       
$val = get($subkey);
       
if (!($val === false)) $dest[$subkey= $val;
       }
       
return $dest;
   } 
else {
       
return $this->_getConForKey($key)->get($key);
   }
   }

   
public function set($key, $var, $compress=0, $expire=0) {
   
return $this->_getConForKey($key)->set($key, $var, $compress, $expire);
   }

   
public function add($key, $var, $compress=0, $expire=0) {
   
return $this->_getConForKey($key)->add($key, $var, $compress, $expire);
   }

   
public function replace($key, $var, $compress=0, $expire=0) {
   
return $this->_getConForKey($key)->replace
       (
$key, $var, $compress, $expire);
   }

   
public function delete($key, $timeout=0) {
   
return $this->_getConForKey($key)->delete($key, $timeout);
   }

   
public function increment($key, $value=1) {
   
return $this->_getConForKey($key)->increment($key, $value);
   }

   
public function decrement($key, $value=1) {
   
return $this->_getConForKey($key)->decrement($key, $value);
   }

}
?>

难道,4.3.3都装上了吗?好像没有吧,用4.4.4好像都要另外装的

)

3。使用memcache情况,计数器、数据压缩
使用情况一:统计

 

(PHP 4.3.3 or newer is required to use the memcache extension.

<?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_COMPRESSED);
?>


使用情况说明:

前台比较

目前内存
bytes

总共读取
bytes_read

总共写入
bytes_written

压缩前

700085

700081

416

压缩后

1131

1125

13

可能看到压缩后明显占用内存少了不少

 

4。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>';
?>

 

 

 

5。内存超量的测试(set)

 我们把内存设为2M

./memcached -d -m 2 -p 11211 -u root

 

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

//600K左右
$test1str_repeat('jetlee',100000);
//600K左右
$test2str_repeat('jetlee',100000);
//600K左右
$test3str_repeat('李连杰',200000);
//600K左右
$test4str_repeat('连杰李',100000);
//200K
$test5file_get_contents('http://img.pconline.com.cn/images/photoblog/2988177/20068/4/1154688770042_mthumb.JPG');
$test6file_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为什么会失败,不是太了解,,,,,,

 

总结:

示例:

<?php
//
设置篇
if($data = $memcache->get('k',$v)) {
//显示我们的数据
    }
else {
$data = get_from_database; //得到数据源
    if(!$memcache->set('k',$data),MEMCACHE_COMPRESSED) //开始设置
    log();    //不成功,记录失败信息
}
?>

 

  -----------OVER-----------

相关教程:

Linux下Memcached的安装及配置:http://blog.haohtml.com/archives/364
基于 PHP5 & JQuery 的 Memcached 管理监控工具:http://www.junopen.com/memadmin/

利用memcached构建高性能的Web应用程序

面临的问题

    对于高并发高访问的Web应用程序来说,数据库存取瓶颈一直是个令人头疼的问题。特别当你的程序架构还是建立在单数据库模式,而一个数据池连接数峰值已经达到500的时候,那你的程序运行离崩溃的边缘也不远了。很多小网站的开发人员一开始都将注意力放在了产品需求设计上,缺忽视了程序整体性能,可扩展性等方面的考虑,结果眼看着访问量一天天网上爬,可突然发现有一天网站因为访问量过大而崩溃了,到时候哭都来不及。所以我们一定要未雨绸缪,在数据库还没罢工前,想方设法给它减负,这也是这篇文章的主要议题。

    大家都知道,当有一个request过来后,web服务器交给app服务器,app处理并从db中存取相关数据,但db存取的花费是相当高昂的。特别是每次都取相同的数据,等于是让数据库每次都在做高耗费的无用功,数据库如果会说话,肯定会发牢骚,你都问了这么多遍了,难道还记不住吗?是啊,如果app拿到第一次数据并存到内存里,下次读取时直接从内存里读取,而不用麻烦数据库,这样不就给数据库减负了?而且从内存取数据必然要比从数据库媒介取快很多倍,反而提升了应用程序的性能。

    因此,我们可以在web/app层与db层之间加一层cache层,主要目的:1. 减少数据库读取负担;2. 提高数据读取速度。而且,cache存取的媒介是内存,而一台服务器的内存容量一般都是有限制的,不像硬盘容量可以做到TB级别。所以,可以考虑采用分布式的cache层,这样更易于破除内存容量的限制,同时又增加了灵活性。

Memcached 介绍

    Memcached是开源的分布式cache系统,现在很多的大型web应用程序包括facebook,youtube,wikipedia,yahoo等等都在使用memcached来支持他们每天数亿级的页面访问。通过把cache层与他们的web架构集成,他们的应用程序在提高了性能的同时,还大大降低了数据库的负载。
具体的memcached资料大家可以直接从它的官方网站[1]上得到。这里我就简单给大家介绍一下memcached的工作原理:

    Memcached处理的原子是每一个(key,value)对(以下简称kv对),key会通过一个hash算法转化成hash-key,便于查找、对比以及做到尽可能的散列。同时,memcached用的是一个二级散列,通过一张大hash表来维护。

    Memcached有两个核心组件组成:服务端(ms)和客户端(mc),在一个memcached的查询中,mc先通过计算key的hash值来确定kv对所处在的ms位置。当ms确定后,客户端就会发送一个查询请求给对应的ms,让它来查找确切的数据。因为这之间没有交互以及多播协议,所以memcached交互带给网络的影响是最小化的。

举例说明:考虑以下这个场景,有三个mc分别是X,Y,Z,还有三个ms分别是A,B,C:

设置kv对
X想设置key=”foo”,value=”seattle”
X拿到ms列表,并对key做hash转化,根据hash值确定kv对所存的ms位置
B被选中了
X连接上B,B收到请求,把(key=”foo”,value=”seattle”)存了起来

获取kv对
Z想得到key=”foo”的value
Z用相同的hash算法算出hash值,并确定key=”foo”的值存在B上
Z连接上B,并从B那边得到value=”seattle”
其他任何从X,Y,Z的想得到key=”foo”的值的请求都会发向B

Memcached服务器(ms)

内存分配

默认情况下,ms是用一个内置的叫“块分配器”的组件来分配内存的。舍弃c++标准的malloc/free的内存分配,而采用块分配器的主要目的是为了避免内存碎片,否则操作系统要花费更多时间来查找这些逻辑上连续的内存块(实际上是断开的)。用了块分配器,ms会轮流的对内存进行大块的分配,并不断重用。当然由于块的大小各不相同,当数据大小和块大小不太相符的情况下,还是有可能导致内存的浪费。

同时,ms对key和data都有相应的限制,key的长度不能超过250字节,data也不能超过块大小的限制 --- 1MB。
因为mc所使用的hash算法,并不会考虑到每个ms的内存大小。理论上mc会分配概率上等量的kv对给每个ms,这样如果每个ms的内存都不太一样,那可能会导致内存使用率的降低。所以一种替代的解决方案是,根据每个ms的内存大小,找出他们的最大公约数,然后在每个ms上开n个容量=最大公约数的instance,这样就等于拥有了多个容量大小一样的子ms,从而提供整体的内存使用率。

缓存策略

当ms的hash表满了之后,新的插入数据会替代老的数据,更新的策略是LRU(最近最少使用),以及每个kv对的有效时限。Kv对存储有效时限是在mc端由app设置并作为参数传给ms的。

同时ms采用是偷懒替代法,ms不会开额外的进程来实时监测过时的kv对并删除,而是当且仅当,新来一个插入的数据,而此时又没有多余的空间放了,才会进行清除动作。

缓存数据库查询
现在memcached最流行的一种使用方式是缓存数据库查询,下面举一个简单例子说明:

App需要得到userid=xxx的用户信息,对应的查询语句类似:

“SELECT * FROM users WHERE userid = xxx”

App先去问cache,有没有“user:userid”(key定义可预先定义约束好)的数据,如果有,返回数据;如果没有,App会从数据库中读取数据,并调用cache的add函数,把数据加入cache中。

当取的数据需要更新,app会调用cache的update函数,来保持数据库与cache的数据同步。

从上面的例子我们也可以发现,一旦数据库的数据发现变化,我们一定要及时更新cache中的数据,来保证app读到的是同步的正确数据。当然我们可以通过定时器方式记录下cache中数据的失效时间,时间一过就会激发事件对cache进行更新,但这之间总会有时间上的延迟,导致app可能从cache读到脏数据,这也被称为狗洞问题。(以后我会专门描述研究这个问题)

数据冗余与故障预防

从设计角度上,memcached是没有数据冗余环节的,它本身就是一个大规模的高性能cache层,加入数据冗余所能带来的只有设计的复杂性和提高系统的开支。

当一个ms上丢失了数据之后,app还是可以从数据库中取得数据。不过更谨慎的做法是在某些ms不能正常工作时,提供额外的ms来支持cache,这样就不会因为app从cache中取不到数据而一下子给数据库带来过大的负载。

同时为了减少某台ms故障所带来的影响,可以使用“热备份”方案,就是用一台新的ms来取代有问题的ms,当然新的ms还是要用原来ms的IP地址,大不了数据重新装载一遍。

另外一种方式,就是提高你ms的节点数,然后mc会实时侦查每个节点的状态,如果发现某个节点长时间没有响应,就会从mc的可用server列表里删除,并对server节点进行重新hash定位。当然这样也会造成的问题是,原本key存储在B上,变成存储在C上了。所以此方案本身也有其弱点,最好能和“热备份”方案结合使用,就可以使故障造成的影响最小化。

Memcached客户端(mc)

Memcached客户端有各种语言的版本供大家使用,包括java,c,php,.net等等,具体可参见memcached api page[2]。
大家可以根据自己项目的需要,选择合适的客户端来集成。

缓存式的Web应用程序架构
有了缓存的支持,我们可以在传统的app层和db层之间加入cache层,每个app服务器都可以绑定一个mc,每次数据的读取都可以从ms中取得,如果没有,再从db层读取。而当数据要进行更新时,除了要发送update的sql给db层,同时也要将更新的数据发给mc,让mc去更新ms中的数据。

假设今后我们的数据库可以和ms进行通讯了,那可以将更新的任务统一交给db层,每次数据库更新数据的同时会自动去更新ms中的数据,这样就可以进一步减少app层的逻辑复杂度。如下图:

不过每次我们如果没有从cache读到数据,都不得不麻烦数据库。为了最小化数据库的负载压力,我们可以部署数据库复写,用slave数据库来完成读取操作,而master数据库永远只负责三件事:1.更新数据;2.同步slave数据库;3.更新cache。如下图:

以上这些缓存式web架构在实际应用中被证明是能有效并能极大地降低数据库的负载同时又能提高web的运行性能。当然这些架构还可以根据具体的应用环境进行变种,以达到不同硬件条件下性能的最优化。

未来的憧憬
Memcached的出现可以说是革命性的,第一次让我们意识到可以用内存作为存储媒介来大规模的缓存数据以提高程序的性能。不过它毕竟还是比较新的东西,还需要很多有待优化和改进的地方,例如:
如何利用memcached实现cache数据库,让数据库跑在内存上。这方面,tangent software 开发的memcached_engine[3]已经做了不少工作,不过现在的版本还只是处于实验室阶段。
如何能方便有效的进行批量key清理。因为现在key是散列在不同的server上的,所以对某类key进行大批量清理是很麻烦的。因为memcached本身是一个大hash表,是不具备key的检索功能的。所以memcached是压根不知道某一类的key到底存了多少个,都存在哪些server上。而这类功能在实际应用中却是经常用到。

交流
作者也是刚接触memcached方面的内容,所以严格来说还只是个新手,班门弄斧地说了一大通,如果有不对的地方,还请各位大侠多多指正。当然,如果有什么和memcached方面有关的问题或建议,也欢迎和我联系。
联系Email: rongwei.yang@dianping.com

参考
[1]. Memcached website: http://danga.com/memcached/
[2]. Memcached API Page: http://danga.com/memcached/apis.bml
[3]. memcached_engine: http://tangent.org/506/memcache_engine.html

memcached配置

一、memcached 简介

在很多场合,我们都会听到 memcached 这个名字,但很多同学只是听过,并没有用过或实际了解过,只知道它是一个很不错的东东。这里简单介绍一下,memcached 是高效、快速的分布式内存对象缓存系统,主要用于加速 WEB 动态应用程序。

二、memcached 安装

首先是下载 memcached 了,目前最新版本是 1.1.12,直接从官方网站即可下载到 memcached-1.1.12.tar.gz。除此之外,memcached 用到了 libevent,我下载的是 libevent-1.1a.tar.gz

接下来是分别将 libevent-1.1a.tar.gz 和 memcached-1.1.12.tar.gz 解开包、编译、安装:

# tar -xzf libevent-1.1a.tar.gz
# cd libevent-1.1a
# ./configure --prefix=/usr
# make
# make install
# cd ..
# tar -xzf memcached-1.1.12.tar.gz
# cd memcached-1.1.12
# ./configure --prefix=/usr
# make
# make install

安装完成之后,memcached 应该在 /usr/bin/memcached。

如果在安装过程中提示:

checking for libevent directory... configure: error: libevent is required. You can get it from http://www.monkey.org/~provos/libevent/
If it's already installed, specify its path using --with-libevent=/dir/

解决办法请参考:http://blog.haohtml.com/archives/11664.或者直接执行

yum install libevent-devel

三、运行 memcached 守护程序

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

/usr/bin/memcached -d -m 128 -l 192.168.1.1 -p 11211 -u root

参数解释:

-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 下编译时需要带上 –enable-memcache[=DIR] 选项,Window 下则在 php.ini 中去掉 php_memcache.dll 前边的注释符,使其可用。

除此之外,还有一种方法,可以避开扩展、重新编译所带来的麻烦,那就是直接使用 php-memcached-client

本文选用第二种方式,虽然效率会比扩展库稍差一些,但问题不大。

四、PHP memcached 应用示例

首先 下载 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.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); ?> 

是不是很简单,在实际应用中,通常会把数据库查询的结果集保存到 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 之后,可以减少数据库连接、查询操作,数据库负载下来了,脚本的运行速度也提高了。

之前我曾经写过一篇名为《PHP 实现多服务器共享 SESSION 数据》文章,文中的 SESSION 是使用数据库保存的,在并发访问量大的时候,服务器的负载会很大,经常会超出 MySQL 最大连接数,利用 memcached,我们可以很好地解决这个问题,工作原理如下:

  • 用户访问网页时,查看 memcached 中是否有当前用户的 SESSION 数据,使用 session_id() 作为唯一标识符;如果数据存在,则直接返回,如果不存在,再进行数据库连接,获取 SESSION 数据,并将此数据保存到 memcached 中,供下次使用;
  • 当前的 PHP 运行结束(或使用了 session_write_close())时,会调用 My_Sess::write() 方法,将数据写入数据库,这样的话,每次仍然会有数据库操作,对于这个方法,也需要进行优化。使用一个全局变量,记录用户进入页面时的 SESSION 数据,然后在 write() 方法内比较此数据与想要写入的 SESSION 数据是否相同,不同才进行数据库连接、写入数据库,同时将 memcached 中对应的对象删除,如果相同的话,则表示 SESSION 数据未改变,那么就可以不做任何操作,直接返回了;
  • 那么用户 SESSION 过期时间怎么解决呢?记得 memcached 的 add() 方法有个过期时间参数 $exp 吗?把这个参数值设置成小于 SESSION 最大存活时间即可。另外别忘了给那些一直在线的用户延续 SESSION 时长,这个可以在 write() 方法中解决,通过判断时间,符合条件则更新数据库数据。

清除缓存,php,html,jsp,asp中防止模式窗口页面不更新的情况

清除缓存,php,html,jsp,asp中防止页面不更新的情况
Code:

HTML
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="Mon, 23 Jan 1978 20:52:30 GMT">
ASP
<%
Response.Expires = -1
Response.ExpiresAbsolute = Now() - 1
Response.cachecontrol = "no-cache"
%>

PHP

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");

JSP

response.setHeader("Pragma","No-Cache");
response.setHeader("Cache-Control","No-Cache");
response.setDateHeader("Expires", 0);