• 首页
  • css3教程
  • html5教程
  • jQuery手册
  • php7教程
  • MySQL手册
  • apache手册
  • 位置: php7教程 -> PECL扩展库

    memcached(缓存)

    这个扩展需要 libmemcached客户端库(版本大于等于 1.0.0)。链接memcached服务器时使用SASL认证,需要libmemcached 必须开启SASL选项。Memcached从0.2.0开始,要求PHP版本大于等于5.2.0。

    安装

    如果libmemcached被安装在一个非标准路径,使用--with-libmemcached-dir=DIR 来指定路径,DIR就是libmemcached安装时的prefix参数。这个路径需要包含文件include/libmemcached/memcached.h

    如果要支持压缩就需要zlib。对于非标准安装的zlib库,使用--with-zlib-dir=DIR 来指定zlib安装路径,DIR就是zib安装时的prefix参数。

    session处理器的支持默认是开启的。如果要关闭它,使用选项--disable-memcached-session

    Do not lose your time to install it on Ubuntu just trying "sudo apt-get install php5-memcached". There is something you need to do that sure installing memcached. Anyway...
    Step 1.
    $ sudo apt-get install memcached
    Step 2.
    $ sudo apt-get install php5-memcached
    Step 3.
    $ sudo /etc/init.d/apache2 restart
    Ready!
    What about some test?
    <?php
    error_reporting(E_ALL & ~E_NOTICE);
    $mc = new Memcached();
    $mc->addServer("localhost", 11211);
    $mc->set("foo", "Hello!");
    $mc->set("bar", "Memcached...");
    $arr = array(
      $mc->get("foo"),
      $mc->get("bar")
    );
    var_dump($arr);
    ?>
    Hoping to help someone.
    ~Kerem

    运行时配置

    这些函数的行为受php.ini中的设置影响。

    Memcached配置选项
    名字默认可修改范围更新日志
    memcached.sess_locking1PHP_INI_ALL
    memcached.sess_consistent_hash0PHP_INI_ALL
    memcached.sess_binary0PHP_INI_ALL
    memcached.sess_lock_wait150000PHP_INI_ALL
    memcached.sess_prefixmemc.sess.key.PHP_INI_ALL
    memcached.sess_number_of_replicas0PHP_INI_ALL
    memcached.sess_randomize_replica_read0PHP_INI_ALL
    memcached.sess_remove_failed0PHP_INI_ALL
    memcached.compression_typefastlzPHP_INI_ALL
    memcached.compression_factor1.3PHP_INI_ALL
    memcached.compression_threshold2000PHP_INI_ALL
    memcached.serializerphpPHP_INI_ALL
    memcached.use_sasl0PHP_INI_SYSTEM

    这是配置指令的简短说明。

    memcached.sess_lockinginteger

    开启session支持。有效值: On, Off, 默认值 On.

    memcached.sess_consistent_hashinteger

    Memcached 是否使用一致性哈希保存session。如果为On,session数据保存则使用一致性哈希模式。 使用一致性哈希,可以保证你在增加或删除memcached服务器节点的时候不会导致session大规模的失效。 默认此项是关闭的。

    memcached.sess_binaryinteger

    Memcached session是否使用二进制模式。如果Libmemcached 开启二进制模式。默认值是 Off.

    memcached.sess_lock_waitinteger

    Session 自旋锁等待时间(微秒)。请小心设置此值。值的类型是整数,当此值被设置为0的时候,lock wait的时间将会使用系统默认值,Memcached扩展中默认值是150000。

    memcached.sess_prefixstring

    设置memcached session key的前缀。session前缀最长为219字节长的字符串。默认值是“memc.sess.key.”。

    memcached.sess_number_of_replicasinteger

    使用memcached写session多少个副本。

    memcached.sess_randomize_replica_readinteger

    Memcached session 是否随机复制读。默认值0

    memcached.sess_remove_failedinteger

    是否允许自动剔除出故障的memcached服务器。默认值0

    memcached.compression_typestring

    设置memcached的压缩类型,允许的值为fastlz, zlib。默认值是fastlz(快速无损压缩,性能不错)。

    memcached.compression_factorfloat

    压缩因子. 保存时压缩因子超过设置的极限才会将数据压缩存储。存储压缩条件: plain_len > comp_len * factor。默认是1.3 (节省23%的空间)。

    memcached.compression_thresholdinteger

    压缩阈值。不压缩的序列化值低于此阈值。默认值是2000字节。

    memcached.serializerstring

    设置缓存对象的默认序列化程序。有效值: php, igbinary, json, json_array.

    json

    标准的PHP JSON编码。此序列化程序快速而且是压缩后的数据,但是处理UTF-8编码数据时会不完全实现序列化。请查看JSON扩展。

    json_array

    json序列化,但是反序列化的时候返回数组。

    php

    PHP标准序列化

    igbinary

    二进制序列化

    如果二进制序列化可用,则优先使用二进制序列化,否则使用php标准序列化。

    memcached.use_saslinteger

    链接memcached服务器时启用SASL认证。有效值On, Off。默认值是Off。

    超时时间

    一些存储命令在发送时会包含一个失效值(与一个元素或一个客户端操作请求相关)到服务端。所有这类用法,实际发送的值可以是一个Unix时间戳(自1970年1月1日起至失效时间的整型秒数),或者是一个从现在算起的以秒为单位的数字。对于后一种情况,这个秒数不能超过60×60×24×30(30天时间的秒数);如果失效的值大于这个值, 服务端会将其作为一个真实的Unix时间戳来处理而不是自当前时间的偏移。

    如果失效值被设置为0(默认),此元素永不过期(但是它可能由于服务端为了给其他新的元素分配空间而被删除)。

    The fact that one sets an expiration time does not mean that the keys will expire at that particular time. I'm not sure what is happening in the background, if there is a process like a garbage collector that expire keys, but some function do not activate the expiration check and return the key as valid, for example `getAllKeys` is not atomic and returns even expired keys. 
    $memcached = new Memcached();
    $memcached->set('key','value',10);
    //waiting more than 10 sec
    sleep(20);
    $data = $memcached->getAllKeys(); 
    var_dump($data); // key will still be listed
    $key = $memcached->get('key'); // will trigger the expiration
    A TTL of n seconds will expire between n and n-1 seconds as memcache doesn't use a high-resolution clock internally.
    This is important to consider if you're working with very short TTLs.
    See https://github.com/memcached/memcached/issues/307
    Note that if you pass the expiration time as an offset of seconds then the cache item will expire in current-second + offset, not in now + offset.
    <?php
    $Memcached->add('foo', 42, 2);
    ?>
    This item will expire in n seconds where n > 1 and <= 2, not in exactly 2 seconds.

    结果回调

    Result callbacks方式在通过Memcached::getDelayed()或 Memcached::getDelayedBykey()方法获取元素后,为结果集中每个元素调用一次。 回调函数可以接收到一个Memcached对象合一个数组描述的元素信息,此回调函数不需要返回任何信息。

    Example #1 结果回调示例

    <?php
    $m = new Memcached();
    $m->addServer('localhost', 11211);
    $items = array(
        'key1' => 'value1',
        'key2' => 'value2',
        'key3' => 'value3'
    );
    $m->setMulti($items);
    $m->getDelayed(array('key1', 'key3'), true, 'result_cb');
    function result_cb($memc, $item)
    {
        var_dump($item);
    }
    ?>
    

    以上例程的输出类似于:

    array(3) {
      ["key"]=>
      string(4) "key1"
      ["value"]=>
      string(6) "value1"
      ["cas"]=>
      float(49)
    }
    array(3) {
      ["key"]=>
      string(4) "key3"
      ["value"]=>
      string(6) "value3"
      ["cas"]=>
      float(50)
    }
    
    I was having trouble making method calls with the result callbacks in getDelayed, so I emailed the developer.
    If you want to use a non-static method as a callback, use the following format: array($obj, 'method'); for example:
    <?php
    class foo {
      private $M = false;
      
      public function __construct() {
        $this->M = new Memcached();
        $this->M->addServer('localhost', 11211);    
        $this->M->set('a', 'test');
      }
      public function test() {
        $this->M->getDelayed(array('a'), false, array($this, 'fun'));
      }
      
      public function fun() {
        echo "Great Success!";
      }
    }
    $f = new foo();
    $f->test();
    ?>
    or, alternatively:
    <?php
    class foo {
      public $M = false;
      
      public function __construct() {
        $this->M = new Memcached();
        $this->M->addServer('localhost', 11211);    
        $this->M->set('a', 'test');
      }
      
      public function fun() {
        echo "Great Success!";
      }
    }
    $f = new foo();
    $f->M->getDelayed(array('a'), false, array($f, 'fun'));
    ?>
    Works great, thanks Andrei :)

    通读缓存回调

    通读缓存回调在一个元素没有从服务端检索到的时候被调用。这个回调函数会接收到Memcached对象,请求的key以及 一个引用方式传递的值变量等三个参数。此回调函数负责通过返回true或false来决定在key没有值时设置一个默认值。 如果回调返回true,Memcached会存储"传出参数"(引用传递的值变量)存储的值到memcached服务端并将其返回到原来 的调用函数中。仅仅Memcached::get()和Memcached::getByKey() 支持这类回调,因为Memcache协议不支持在请求多个key时提供未检索到key的信息。

    Example #1 通读回调示例

    <?php
    $m = new Memcached();
    $m->addServer('localhost', 11211);
    $profile_info = $m->get('user:'.$user_id, 'user_info_cb');
    function user_info_cb($memc, $key, &$value)
    {
        $user_id = substr($key, 5);
        /* 从数据库读取个人信息 */
        /* ... */
        $value = $profile_info;
        return true;
    }
    ?>
    
    Or just set the value within the callback with your own custom expiration time and return false. I think it's cleaner.
    This isn't specified anywhere, so I had a gander at the source...
    The expiry on read-through cache set values is set to 0, or forever. This means if you want your key to implicitly expire, don't use the callback methods, instead check for boolean false as a return and manually set the value, at least for now.

    Sessions支持

    memcached提供了一个自定义的session处理器可以被用于存储用户session数据到memcached服务端。一个完全独立的memcached实例将会在内部使用,因此如果需要您可以设置一个不同的服务器池。session的key被存储在前缀memc.sess.key.之下,因此, 如果你对session和通常的缓存使用了同样的服务器池,请注意这一点。译注:另外一个session和通常缓存分离的原因是当通常的缓存占满了memcached服务端后,可能会导致你的session被从缓存中踢除,导致用户莫名的掉线。

    session.save_handlerstring

    设置为memcached开启memcached的session处理器。

    session.save_pathstring

    定义一个逗号分隔的hostname:port样式的session缓存服务器池,例如:"sess1:11211, sess2:11211".

    If you want to use 'memcacheD' extention not 'memcache' (there are two diffrent extentions) for session control, you should pay attention to modify php.ini
    Most web resource from google is based on memcache because It's earlier version than memcacheD. They will say as following
    session.save_handler = memcache
    session.save_path = "tcp://localhost:11211"
    But it's not valid when it comes to memcacheD
    you should modify php.ini like that
    session.save_handler = memcached
    session.save_path = "localhost:11211"
    Look, there is no protocol indentifier
    If you are setting data to the session and it immediately disappears and you aren't getting any warnings in your PHP error log, it's probably because your sessions expired sometime in the 1970s.
    Somewhere between memcached 1.0.2 and 2.1.0, the memcached session handler became sensitive to the 30-day TTL gotcha (aka "transparent failover"). If your session.gc_maxlifetime is greater than 2592000 (30 days), the value is treated as a unix timestamp instead of a relative seconds count.
    This issue is likely to impact anyone with long-running sessions who is upgrading from Ubuntu 12.04 to 14.04.
    The documentation is not complete, you can also pass the weight of each server and you can use sockets if you want. In your PHP ini:
    <?php
    // Sockets with weight in the format socket_path:port:weight
    session.save_path = "/path/to/socket:0:42"
    // Or more than one so that weight makes sense?
    session.save_path = "/path/to/socket_x:0:42,/path/to/socket_y:0:666"
    ?>
    And if you should ever want to access these servers in PHP:
    <?php
    $servers = explode(",", ini_get("session.save_path"));
    $c = count($servers);
    for ($i = 0; $i < $c; ++$i) {
     $servers[$i] = explode(":", $servers[$i]);
    }
    $memcached = new \Memcached();
    call_user_func_array([ $memcached, "addServers" ], $servers);
    print_r($memcached->getAllKeys());
    ?>
    
    If you are using the memcache class for session handling your key is the PHP session ID. This is different than when using the memcached class.
    Example with memcache:
    GET nphu2u8eo5niltfgdbc33ajb62
    Example with memcached:
    GET memc.sess.key.nphu2u8eo5niltfgdbc33ajb62
    For memcached, the prefix is set in the config:
    memcached.sess_prefix = "memc.sess.key."
    This extension supports Session-locking!
    by default
    MEMC_SESS_LOCK_ATTEMPTS  30
    MEMC_SESS_LOCK_WAIT    100000
    MEMC_SESS_LOCK_EXPIRATION 30
    in case of multiples memcached servers,
    the separator is a semicolon ( ; ) not a comma as written 
    example:
    session.save_path = "sess1:11211; sess2:11211"
    Is important to address that memcached is not concurrent just as regular PHP sessions.
    If you have two tabs and one of them takes too long to respond and try to log out on the second, the memcached server won't respond.
    short mention: Memcached has authentication support.
    While the previous poster has a point that Memcached can and will cleanup to make room for it's keys, the likelihood of active sessions (due to the likelihood that they will be written to again within 30 seconds) is fairly low provided you have your memory allocation properly alloted.
    It seems a few people think saving sessions in memcache is more secure compared to saving in file-system (/tmp) especially when the discussion is about shared hosting.
    This is not true. memcache has NO authentication; everybody & anybody can read session.save_path (which will contain the memcached daemon address).
    FastCGI (PHP-FPM) is much much better when you're considering security and shared hosting.
    If you want to share sessions across multiple servers transparently without having headaches of adding custom handlers, you can use NFS or something similar.

    Memcached类

    (PECL memcached >= 0.1.0)

    表征到memcached服务集群的连接。

    Memcached 
    {
    	__construct ([ string $persistent_id ] )
    	public add ( string $key , mixed $value [, int $expiration ] ) : bool
    	public addByKey ( string $server_key , string $key , mixed $value [, int $expiration ] ) : bool
    	public addServer ( string $host , int $port [, int $weight = 0 ] ) : bool
    	public addServers ( array $servers ) : bool
    	public append ( string $key , string $value ) : bool
    	public appendByKey ( string $server_key , string $key , string $value ) : bool
    	public cas ( float $cas_token , string $key , mixed $value [, int $expiration ] ) : bool
    	public casByKey ( float $cas_token , string $server_key , string $key , mixed $value [, int $expiration ] ) : bool
    	public decrement ( string $key [, int $offset = 1 ] ) : int
    	public decrementByKey ( string $server_key , string $key [, int $offset = 1 [, int $initial_value = 0 [, int $expiry = 0 ]]] ) : int
    	public delete ( string $key [, int $time = 0 ] ) : bool
    	public deleteByKey ( string $server_key , string $key [, int $time = 0 ] ) : bool
    	public deleteMulti ( array $keys [, int $time = 0 ] ) : array
    	public deleteMultiByKey ( string $server_key , array $keys [, int $time = 0 ] ) : bool
    	public fetch ( void ) : array
    	public fetchAll ( void ) : array
    	public flush ([ int $delay = 0 ] ) : bool
    	public get ( string $key [, callback $cache_cb [, float &$cas_token ]] ) : mixed
    	public getAllKeys ( void ) : array
    	public getByKey ( string $server_key , string $key [, callback $cache_cb [, float &$cas_token ]] ) : mixed
    	public getDelayed ( array $keys [, bool $with_cas [, callback $value_cb ]] ) : bool
    	public getDelayedByKey ( string $server_key , array $keys [, bool $with_cas [, callback $value_cb ]] ) : bool
    	public getMulti ( array $keys [, int $flags ] ) : mixed
    	public getMultiByKey ( string $server_key , array $keys [, string &$cas_tokens [, int $flags ]] ) : array
    	public getOption ( int $option ) : mixed
    	public getResultCode ( void ) : int
    	public getResultMessage ( void ) : string
    	public getServerByKey ( string $server_key ) : array
    	public getServerList ( void ) : array
    	public getStats ( void ) : array
    	public getVersion ( void ) : array
    	public increment ( string $key [, int $offset = 1 ] ) : int
    	public incrementByKey ( string $server_key , string $key [, int $offset = 1 [, int $initial_value = 0 [, int $expiry = 0 ]]] ) : int
    	public isPersistent ( void ) : bool
    	public isPristine ( void ) : bool
    	public prepend ( string $key , string $value ) : bool
    	public prependByKey ( string $server_key , string $key , string $value ) : bool
    	public quit ( void ) : bool
    	public replace ( string $key , mixed $value [, int $expiration ] ) : bool
    	public replaceByKey ( string $server_key , string $key , mixed $value [, int $expiration ] ) : bool
    	public resetServerList ( void ) : bool
    	public set ( string $key , mixed $value [, int $expiration ] ) : bool
    	public setByKey ( string $server_key , string $key , mixed $value [, int $expiration ] ) : bool
    	public setMulti ( array $items [, int $expiration ] ) : bool
    	public setMultiByKey ( string $server_key , array $items [, int $expiration ] ) : bool
    	public setOption ( int $option , mixed $value ) : bool
    	public setOptions ( array $options ) : bool
    	public setSaslAuthData ( string $username , string $password ) : void
    	public touch ( string $key , int $expiration ) : bool
    	public touchByKey ( string $server_key , string $key , int $expiration ) : bool
    }