在PHP中使用memcached提高动态网站性能, memcached, memcache, memcached数据库缓存类

 

确认是否已经安装memcached:Verify Installation

php -m | grep memcached

 

视频:

 

memcached 函数

看官网:http://php.net/manual/zh/book.memcached.php

Memcached — Memcached类

 

memcached 自定义类 (兼容 memcache 和 memcached)

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');

class Mmemcached
{
    private $m;
    private $client_type;
    private $skip_prefix = false;
    private $prefix      = MEMCACHE_PREFIX;
    protected $errors    = [];

    public function __construct($params = array())
    {
        $this->prefix      = $params['prefix'] ?? MEMCACHE_PREFIX;
        $this->client_type = trim(ucfirst($params['engine'] ?? ($params['client_type'] ?? MEMCACHE_ENGINE)));
        $servers = $params['servers'] ?? ($params['server'] ?? array(MEMCACHE_HOST, MEMCACHE_PORT, MEMCACHE_WEIGHT));

        if ($this->client_type)
        {
            // Which one should be loaded
            switch ($this->client_type)
            {
                case 'Memcached': $this->m = new Memcached(); break;
                case 'Memcache':

                    $this->m = new Memcache();
                    // Set Automatic Compression Settings
                    $auto_compress_tresh   = $params['auto_compress_tresh']   ?? ($params['compress_tresh']   ?? MEMCACHE_COMPRESSION);
                    $auto_compress_savings = $params['auto_compress_savings'] ?? ($params['compress_savings'] ?? MEMCACHE_COMPRESS_SAVINGS);

                    if ($auto_compress_tresh) $this->setcompressthreshold($auto_compress_tresh, $auto_compress_savings);

                break;
            }

            $this->auto_connect($servers);
        }

        return $this;
    }

    /*
    +-------------------------------------+
        Name: auto_connect
        Purpose: runs through all of the servers defined in
        the configuration and attempts to connect to each
        @param return : none
    +-------------------------------------+
    */

    private function auto_connect($servers = array())
    {
        if($servers) foreach ($servers as $key => $server) $this->add_server($server);
    }

    /*
    +-------------------------------------+
        Name: add_server
        Purpose:
        @param return : TRUE or FALSE
    +-------------------------------------+
    */

    public function add_server($server = array())
    {
        $host   = $server['host']   ?? MEMCACHE_HOST;
        $port   = $server['port']   ?? MEMCACHE_PORT;
        $weight = $server['weight'] ?? MEMCACHE_WEIGHT;

        return $this->m->addServer($host, $port, $weight);
    }

    /*
    +-------------------------------------+
        Name: add
        Purpose: add an item to the memcache server(s)
        @param return : TRUE or FALSE
    +-------------------------------------+
    */

    public function add($key = null, $value = null, $expiration = null)
    {
        if (is_null($expiration)) $expiration = MEMCACHE_EXPIRATION;

        if (is_array($key))
        {
            foreach ($key as $multi)
            {
                if (!isset($multi['expiration']) || $multi['expiration'] == '') $multi['expiration'] = MEMCACHE_EXPIRATION;
                $this->add($this->key_name($multi['key']), $multi['value'], $multi['expiration']);
            }
        }
        else
        {
            switch ($this->client_type)
            {
                case 'Memcache': $add_status = $this->m->add($this->key_name($key), $value, MEMCACHE_COMPRESSION, $expiration); break;
                default:
                case 'Memcached': $add_status = $this->m->add($this->key_name($key), $value, $expiration); break;
            }

            return $add_status;
        }
    }

    /*
    +-------------------------------------+
        Name: set
        Purpose: similar to the add() method but uses set
        @param return : TRUE or FALSE
    +-------------------------------------+
    */

    public function set($key = null, $value = null, $expiration = null)
    {
        if (is_null($expiration)) $expiration = MEMCACHE_EXPIRATION;

        if (is_array($key))
        {
            foreach ($key as $multi)
            {
                if (!isset($multi['expiration']) || $multi['expiration'] == '') $multi['expiration'] = MEMCACHE_EXPIRATION;
                $this->set($this->key_name($multi['key']), $multi['value'], $multi['expiration']);
            }
        }
        else
        {
            switch ($this->client_type)
            {
                case 'Memcache': $add_status = $this->m->set($this->key_name($key), $value, MEMCACHE_COMPRESSION, $expiration); break;
                default:
                case 'Memcached': $add_status = $this->m->set($this->key_name($key), $value, $expiration); break;
            }

            return $add_status;
        }
    }

    /*
    +-------------------------------------+
        Name: get
        Purpose: gets the data for a single key or an array of keys
        @param return : array of data or multi-dimensional array of data
    +-------------------------------------+
    */

    public function get($key = null)
    {
        $output = false;

        if ($this->m)
        {
            if (is_null($key)) $this->errors[] = 'The key value cannot be NULL';

            if (is_array($key))
            {
                foreach ($key as $n => $k) $key[$n] = $this->key_name($k);
                $output = $this->m->getMulti($key);
            }
            else $output = $this->m->get($this->key_name($key));
        }

        return $output;
    }

    /*
    +-------------------------------------+
        Name: delete
        Purpose: deletes a single or multiple data elements from the memached servers
        @param return : none
    +-------------------------------------+
    */

    public function delete($key, $expiration = null)
    {
        if (is_null($key)) $this->errors[] = 'The key value cannot be NULL';
        if (is_null($expiration)) $expiration = MEMCACHE_DELETE_EXPIRATION;

        if (is_array($key)) foreach ($key as $multi) $this->delete($multi, $expiration);
        else $this->m->delete($this->key_name($key), $expiration);
    }

    /*
    +-------------------------------------+
        Name: replace
        Purpose: replaces the value of a key that already exists
        @param return : none
    +-------------------------------------+
    */

    public function replace($key = null, $value = null, $expiration = null)
    {
        if (is_null($expiration)) $expiration = MEMCACHE_EXPIRATION;

        if (is_array($key))
        {
            foreach ($key as $multi)
            {
                if (!isset($multi['expiration']) || $multi['expiration'] == '') $multi['expiration'] = MEMCACHE_EXPIRATION;
                $this->replace($multi['key'], $multi['value'], $multi['expiration']);
            }
        }
        else
        {
            switch ($this->client_type)
            {
                case 'Memcache': $replace_status = $this->m->replace($this->key_name($key), $value, MEMCACHE_COMPRESSION, $expiration); break;
                default:
                case 'Memcached': $replace_status = $this->m->replace($this->key_name($key), $value, $expiration); break;
            }

            return $replace_status;
        }
    }

    /*
    +-------------------------------------+
        Name: increment
        Purpose: increments a value
        @param return : none
    +-------------------------------------+
    */

    public function increment($key = null, $by = 1)
    {
        return $this->m->increment($this->key_name($key), $by);
    }

    /*
    +-------------------------------------+
        Name: decrement
        Purpose: decrements a value
        @param return : none
    +-------------------------------------+
    */

    public function decrement($key = null, $by = 1)
    {
        return $this->m->decrement($this->key_name($key), $by);
    }

    /*
    +-------------------------------------+
        Name: flush
        Purpose: flushes all items from cache
        @param return : none
    +-------------------------------------+
    */

    public function flush()
    {
        return $this->m->flush();
    }

    /*
    +-------------------------------------+
        Name: getversion
        Purpose: Get Server Vesion Number
        @param Returns a string of server version number or FALSE on failure.
    +-------------------------------------+
    */

    public function getversion()
    {
        return $this->m->getVersion();
    }

    /*
    +-------------------------------------+
        Name: get_stats
        Purpose: Get Server Stats
        Possible: "reset, malloc, maps, cachedump, slabs, items, sizes"
        @param returns an associative array with server's statistics. Array keys correspond to stats parameters and values to parameter's values.
    +-------------------------------------+
    */

    public function get_stats($type = 'items')
    {
        switch ($this->client_type)
        {
            case 'Memcache': $stats = $this->m->getStats($type); break;
            default:
            case 'Memcached': $stats = $this->m->getStats(); break;
        }

        return $stats;
    }

    /*
    +-------------------------------------+
        Name: setcompresstreshold
        Purpose: Set When Automatic compression should kick-in
        @param return TRUE/FALSE
    +-------------------------------------+
    */

    public function setcompressthreshold($tresh, $savings = 0.2)
    {
        $setcompressthreshold_status = null;

        switch ($this->client_type)
        {
            case 'Memcache': $setcompressthreshold_status = $this->m->setCompressThreshold($tresh, $savings); break;
            default: $setcompressthreshold_status = true; break;
        }

        return $setcompressthreshold_status;
    }

    public function skip_prefix($prefix = true)
    {
        $this->skip_prefix = $prefix;
        return $this;
    }

    /*
    +-------------------------------------+
        Name: key_name
        Purpose: standardizes the key names for memcache instances
        @param return : md5 key name
    +-------------------------------------+
    */

    private function key_name($key)
    {
        $prefix = $this->prefix;
        if($this->skip_prefix) $this->prefix = is_string($this->skip_prefix) ? $this->skip_prefix : '';

        $output = md5(str_replace(' ', '', strtolower($this->prefix.$key)));

        if($this->skip_prefix)
        {
            $this->prefix      = $prefix;
            $this->skip_prefix = false;
        }

        return $output;
    }

    /*
    +--------------------------------------+
        Name: isConected
        Purpose: Check if the memcache server is connected.
    +--------------------------------------+
    */

    public function isConnected()
    {
        foreach ($this->get_stats() as $key => $server) {
            if ($server['pid'] == -1) {
                return false;
            }

            return true;
        }
    }
}

 

前提是要有个配置文件:

// --------------------------------------------------------------------------
// Configs
// --------------------------------------------------------------------------
define('MEMCACHE_ENGINE', 'Memcache');
define('MEMCACHE_HOST',   '127.0.0.1');
define('MEMCACHE_PORT',   11211);
define('MEMCACHE_WEIGHT', 1);
define('MEMCACHE_PREFIX', '');
define('MEMCACHE_COMPRESSION',      false);
define('MEMCACHE_COMPRESS_SAVINGS',  0.2);
define('MEMCACHE_EXPIRATION',  86400);
define('MEMCACHE_DELETE_EXPIRATION',  0);

// --------------------------------------------------------------------------
// Servers
// --------------------------------------------------------------------------
$memcached['servers'] =
    [
        'default' => [
            'host'            => MEMCACHE_HOST,
            'port'            => MEMCACHE_PORT,
            'weight'          => MEMCACHE_WEIGHT,
            'persistent'      => false,
        ],
    ];
// --------------------------------------------------------------------------
// Configuration
// --------------------------------------------------------------------------
$memcached['config'] = [
    'engine'                 => MEMCACHE_ENGINE,           // Set which caching engine you are using. Acceptable values: Memcached or Memcache
    'prefix'                 => MEMCACHE_PREFIX,          // Prefixes every key value (useful for multi environment setups)
    'compression'            => false,                    // Default: FALSE or MEMCACHE_COMPRESSED Compression Method (Memcache only).
    // Not necessary if you already are using 'compression'
    'auto_compress_tresh'      => false,                    // Controls the minimum value length before attempting to compress automatically.
    'auto_compress_savings'    => 0.2,                        // Specifies the minimum amount of savings to actually store the value compressed. The supplied value must be between 0 and 1.
    'expiration'               => 3600,                    // Default content expiration value (in seconds)
    'delete_expiration'        => 0,                        // Default time between the delete command and the actual delete action occurs (in seconds)
];

 

用法:

$app_products = $this->memcached->get('import_list_'.$start.$limit);
if(!$app_products)
{
    $app_products = $this->db
        ->table(TABLE_APP_PRODUCTS)
        ->fields('id, store_id, product_id, title, body_html, product_type, tags')
        ->limit($start.','.$limit)
        ->desc('id')
        ->where(array('store_id' => $this->_current_store_id, 'is_deleted' => 0, 'published' => 0))
        ->pages(true, true);

    $this->memcached->set('import_list_'.$start.$limit, $app_products);
}

 

其他操作:

1. 启动memcached

memcached -p 11211 -d -u root -P /tmp/memcached.pid
  1. -P是表示使用TCP,默认端口为11211
  2. -d表示后台启动一个守护进程(daemon)
  3. -u表示指定root用户启动,默认不能用root用户启动
  4. -P表示进程的pid存放地点,此处“p”为大写“P”
  5. -l,后面跟IP地址,手工指定监听IP地址,默认所有IP都在监听
  6. -m后面跟分配内存大小,以MB为单位,默认为64M
  7. -c最大运行并发连接数,默认为1024
  8. -f 块大小增长因子,默认是1.25
  9. -M 内存耗尽时返回错误,而不是删除项,即不用LRU算法  在64位系统中,会报libevent-1.4.so.2文件无法找到,解决办法是把32位目录里的同名文件链接至64位目录中,即像windows那样建立快捷方式。 Shell > /usr/local/lib/libevent-1.4.so.2 /usr/lib64/libevent-1.4.so.2 启动后如果发现没有端口在监听,是因为命动命令时带pid参数的“p”是大写“P”,你可能写成小写了。
  10. 接到memcache: shell>telnet 127.0.0.1 11211

2. 命令行直接操作命令

  1. 存数据。
    1. set:添加一个新条目到memcached或是用新的数据替换替换掉已存在的条目
    2. add:当KEY不存在的情况下,它向memcached存数据,否则,返回NOT_STORED响应
    3. replace:当KEY存在的情况下,它才会向memcached存数据,否则返回NOT_STORED响应
    4. cas:改变一个存在的KEY值 ,但它还带了检查的功能
    5. append:在这个值后面插入新值
    6. prepend:在这个值前面插入新值
  2. 取,有两个命令项:
    1. get:取单个值 ,从缓存中返回数据时,将在第一行得到KEY的名字,flag的值和返回的value长度,真正的数据在第二行,最后返回END,如KEY不存在,第一行就直接返回END
    2. Get_multi:一次性取多个值
  3. 删除,一个命令:
    1. delete

 

3. Memcached的分布式算法:

当向memcached集群存入/取出key/value时,memcached客户端程序根据一定的算法计算存入哪台服务器,然后再把key/value值存到此服务器中。也就是说,存取数据分二步走,第一步,选择服务器,第二步存取数据。

在PHP中使用memcached提高动态网站性能, memcached, memcache, memcached数据库缓存类
在PHP中使用memcached提高动态网站性能, memcached, memcache, memcached数据库缓存类
  1. 分布式算法(Consistent Hashing):
    选择服务器算法有两种,一种是根据余数来计算分布,另一种是根据散列算法来计算分布。
  1. 余数算法: 先求得键的整数散列值,再除以服务器台数,根据余数确定存取服务器,这种方法计算简单,高效,但在memcached服务器增加或减少时,几乎所有的缓存都会失效。
  2. 散列算法:
    先算出memcached服务器的散列值,并将其分布到0到2的32次方的圆上,然后用同样的方法算出存储数据的键的散列值并映射至圆上,最后从数据映射到的位置开始顺时针查找,将数据保存到查找到的第一个服务器上,如果超过2的32次方,依然找不到服务器,就将数据保存到第一台memcached服务器上。如果添加了一台memcached服务器,只在圆上增加服务器的逆时针方向的第一台服务器上的键会受到影响。

    在PHP中使用memcached提高动态网站性能, memcached, memcache, memcached数据库缓存类
    在PHP中使用memcached提高动态网站性能, memcached, memcache, memcached数据库缓存类

 

4. Memcache的管理与性能监控:

可以通过命令行直接管理与监控也可通过nagios,cacti等web软件进行监控
命令行:Shell>telnet 127.0.0.1 1211 //如果在启动时指定了IP及端口号,这里要作相应改动,连接成功后命令

  1. stats:统计memcached的各种信息
  2. stats reset:重新统计数据
  3. stats slabs,显示slabs信息,可以详细看到数据的分段存储情况
  4. stats items:显示slab中的item数目
  5. stats cachedump 1 0:列出slabs第一段里存的KEY值
  6. set|get:保存或获取数据
  7. STAT evictions 0:表示要腾出新空间给新的item而移动的合法item数目
在PHP中使用memcached提高动态网站性能, memcached, memcache, memcached数据库缓存类
在PHP中使用memcached提高动态网站性能, memcached, memcache, memcached数据库缓存类

 

参考:

PHP: Memcached安装, Memcache/Memcached的PHP操作手册, Memcached使用, Memcached教程

 

 

本文:在PHP中使用memcached提高动态网站性能, memcached, memcache, memcached数据库缓存类

Loading

2 Comments

Add a Comment

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.