Memcached是一款开源、高性能、分布式内存对象缓存系统,可应用各种需要缓存的场景,其主要目的是通过降低对数据库的访问来加速web应用程序。它是一个基于内存的“键值对”存储,用于存储数据库调用、API调用或页面引用结果的直接数据,如字符串、对象等。

分布式缓存memcached_memcached

一、memcached既不是一个代码加速器,也不是数据库中间件。其具有以下特点

   ⑴内置内存存储方式:为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。重启memcached,重启操作系统会导致全部数据消失;

   ⑵简单key/value存储:服务器不关心数据本身的意义及结构,只要是可序列化数据即可。存储项由“键、过期时间、可选的标志及数据”四个部分组成;

   ⑶O(1)的执行效率;

   ⑷基于libevent的事件处理:libevent是个函数库,它将Linux的epoll、BSD类操作系统的kqueue等时间处理功能封装成统一的接口。memcached使用这个libevent库,能发挥高性能;

   ⑸功能的实现一半依赖于客户端,一半基于服务器端:客户负责发送存储项至服务器端、从服务端获取数据以及无法连接至服务器时采用相应的动作;服务端负责接收、存储数据,并设置数据项的过期时长;

   ⑹各服务器间不会通信以共享信息;memcached虽然是分布式缓存服务器,但服务器端并没有分布式功能,此功能主要通过客户端实现;

   ⑺清理超期数据:默认情况下,Memcached是一个LRU缓存,同时,它按事先预订的时长清理超期数据;但事实上,memcached不会删除任何已缓存数据,只是在其过期之后不再为客户端所见;而且,memcached也不会真正按期限清理缓存,而仅是当get命令到达时检查其时长,发现过期才清理;


二、memcached的内存管理

分布式缓存memcached_数据_02

    可参考http://blog.csdn.net/dato/article/details/1968663


三、安装memcached

   1、memcached依赖于libevent实现并发处理,先要安装后libevent包,不过此包是系统标配;

       yum -y install memcached

   2、启动memcached服务

       service memcached start   #memcached默认监听在TCP和UDP的11211号端口

[root@node4 ~]# rpm -q libevent
libevent-1.4.13-4.el6.x86_64
[root@node4 ~]# yum -y install memcached
...
[root@node4 ~]# rpm -ql memcached
/etc/rc.d/init.d/memcached
/etc/sysconfig/memcached   #主配置文件
/usr/bin/memcached   #主程序
/usr/bin/memcached-tool
/usr/share/doc/memcached-1.4.4
...
[root@node4 ~]# vim /etc/sysconfig/memcached 

PORT="11211"
USER="memcached"
MAXCONN="1024"   #并发连接数
CACHESIZE="64"   #用于缓存的空间大小   
OPTIONS=""
[root@node4 ~]# service memcached start
...
[root@node4 ~]# ss -tunl
Netid State      Recv-Q Send-Q               Local Address:Port                 Peer Address:Port 
 
udp   UNCONN     0      0                       :::11211                          :::*     
tcp   LISTEN     0      128                     :::11211                          :::*     
tcp   LISTEN     0      128                      *:11211                           *:*     
...

   3、memcached主程序常用选项

       -l <ip_addr>:指定进程监听的地址

       -d: 以守护进程模式运行;

       -u <username>:以指定的用户身份运行memcached进程;

       -m <num>:用于缓存数据的最大内存空间,单位为MB,默认为64MB;

       -c <num>:最大支持的并发连接数,默认为1024;

       -p <num>: 指定监听的TCP端口,默认为11211;

       -P <filename>: pid文件

       -U <num>:指定监听的UDP端口,默认为11211,0表示关闭UDP端口;

       -t <threads>:用于处理入站请求的最大线程数,仅在memcached编译时开启了支持线程才有效;

       -f <num>:设定Slab Allocator定义预先分配内存空间大小固定的块时使用的增长因子;默认为1.25

       -M:当内存空间不够使用时返回错误信息,而不是按LRU算法利用空间;

       -n: 指定最小的slab chunk大小;单位是字节;

       -S: 启用sasl进行用户认证;

[root@node4 ~]# memcached -u memcached -vv
slab class   1: chunk size        96 perslab   10922
slab class   2: chunk size       120 perslab    8738
slab class   3: chunk size       152 perslab    6898
slab class   4: chunk size       192 perslab    5461
slab class   5: chunk size       240 perslab    4369
slab class   6: chunk size       304 perslab    3449
slab class   7: chunk size       384 perslab    2730
slab class   8: chunk size       480 perslab    2184
slab class   9: chunk size       600 perslab    1747
slab class  10: chunk size       752 perslab    1394
...
[root@node4 ~]# memcached-tool 127.0.0.1
  #  Item_Size  Max_age   Pages   Count   Full?  Evicted Evict_Time OOM
  1      96B     80717s       1       1      no        0        0    0
[root@node4 ~]# memcached-tool 127.0.0.1 stats
#127.0.0.1:11211   Field       Value
                    ...
            pointer_size          64
           rusage_system    1.216815
             rusage_user    1.241811
                 threads           4
                    time  1463497553
       total_connections          17
             total_items           7
                  uptime       81292
                 version       1.4.4


四、Memcached提供了为数不多的几个命令来完成与服务器端的交互,这些命令基于memcached的协议实现。

  1、存储类命令:set, add, replace, append, prepend

      用法:<command> <key> <flag> <expire> <size>

          <value>

         例如:set user 0 0 8   #过期时长为0表示永不过期

             jerry

      set:无论如何都存储,数据不存在时存储,数据存在时更新

      add:数据不存在时进行添加

      replace:替换

      append:将数据追加到当前缓存数据的之后

      prepend:将数据追加到当前缓存数据的之前

  2、获取数据类命令:get, delete, incr/decr

      get key1 key2...:读取 

      incr/decr key:对数字型的对象进行增/减操作     

  3、统计类命令:

      stats:查看memcached运行状态

      stats items:

      stats slabs:显示各个slab的信息,包括chunk的大小、数目、使用情况等

      stats sizes:输出所有item的大小和个数

  4、清理命令:

      delete key:删除

      flush_all:将当前所有缓存数据设置为过期,但不会释放内存

[root@node4 ~]# telnet 127.0.0.1 11211   #使用telnet命令测试memcached的使用
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
set user 0 60 5 
jerry
STORED
add gender 0 60 6
female
STORED
get user
VALUE user 0 5
jerry
END
delete gender
DELETED
stats
STAT pid 37622
STAT uptime 80761
STAT time 1463497022
STAT version 1.4.4
STAT pointer_size 64
STAT rusage_user 1.241811
STAT rusage_system 1.173821
STAT curr_connections 10
STAT total_connections 15
STAT connection_structures 11
...
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT bytes 74
STAT curr_items 1
STAT total_items 7
STAT evictions 0
END


五、PHP作为memcached的客户端

  1、在php-fpm服务器上安装PHP的memcache扩展

      # wget https://pecl.php.net/get/memcache-2.2.7.tgz

      # tar xf memcache-2.2.7.tgz

      # cd memcache-2.2.7

      # /usr/local/php/bin/phpize   生成configure文件

      # ./configure --with-php-config=/usr/local/php/bin/php-config --enable-memcache

      # make && make install

    安装完后会有类似以下的提示:

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

  2、编辑/usr/local/php/lib/php.ini,在“动态模块”相关的位置添加memcache扩展的路径:

      extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20130626/memcache.so


  ◆补充:rpm方式安装的php-fpm如何加载扩展模块

      此种情况需要先安装php-devel包,该包能提供phpize和php-config两个二进制程序。其余步骤与上述类似,根据实际情况做适当修改即可。

      # yum -y install php-devel

      ......

      # ./configure --with-php-config=/usr/bin/php-config --enable-memcache

      ...

      cp tmp-php.ini /etc/php.d/

      vim /etc/php.d/tmp-php.ini

        extension=/usr/lib64/php/modules/memcache.so


   示例:

分布式缓存memcached_数据_03

  

#此例中的php-fpm是使用rpm方式安装的,所以若欲对其做扩展就要先安装php-devel
[root@node1 ~]# yum -y install php-devel
...
[root@node1 ~]# rpm -ql php-devel
/etc/rpm/macros.php
/usr/bin/php-config
/usr/bin/phpize
/usr/include/php
...
[root@node1 ~]# wget https://pecl.php.net/get/memcache-2.2.7.tgz    #下载memcache扩展源码包
...
[root@node1 ~]# tar xf memcache-2.2.7.tgz 
[root@node1 ~]# cd memcache-2.2.7
[root@node1 memcache-2.2.7]# phpize    #生成configure文件
Configuring for:
PHP Api Version:         20090626
Zend Module Api No:      20090626
Zend Extension Api No:   220090626
[root@node1 memcache-2.2.7]# ls
acinclude.m4    config9.m4    config.sub    CREDITS      Makefile.global             memcache.php        memcache_standard_hash.c  README
aclocal.m4      config.guess  configure     example.php  memcache.c                  memcache_queue.c    missing                   run-tests.php
autom4te.cache  config.h.in   configure.in  install-sh   memcache_consistent_hash.c  memcache_queue.h    mkinstalldirs
build           config.m4     config.w32    ltmain.sh    memcache.dsp                memcache_session.c  php_memcache.h
[root@node1 memcache-2.2.7]# ./configure --with-php-config=/usr/bin/php-config --enable-memcache   #编译
...
[root@node1 memcache-2.2.7]# make && make install
...
Build complete.
Don't forget to run 'make test'.

Installing shared extensions:     /usr/lib64/php/modules/   #memcache模块的目录


[root@node1 memcache-2.2.7]# ls /usr/lib64/php/modules/
curl.so  fileinfo.so  json.so  memcache.so  phar.so  zip.so
[root@node1 memcache-2.2.7]# cp tmp-php.ini /etc/php.d/
[root@node1 memcache-2.2.7]# vim /etc/php.d/tmp-php.ini
在Dynamic Extensions段下添加:
extension=/usr/lib64/php/modules/memcache.so
[root@node1 memcache-2.2.7]# service php-fpm restart
...

分布式缓存memcached_数据_04


  3、对memcached功能进行测试,在网站目录中建立测试页面test.php,添加如下内容:

     <?php

       $mem = new Memcache;

       $mem->connect("192.168.30.14", 11211) or die("Could not connect");

       $version = $mem->getVersion();

       echo "Server's version: ".$version."<br/>\n";

       $mem->set('hellokey', 'Hello World', 0, 600) or die("Failed to save data at the memcached server");

       echo "Store data in the cache (data will expire in 600 seconds)<br/>\n";

       $get_result = $mem->get('hellokey');

       echo "$get_result is from memcached server.";         

      ?>

      如果有输出“Hello World is from memcached.”等信息,则表明memcache已经能够正常工作。

[root@node1 ~]# vim /web/scripts/memtest.php    #创建一个测试页

<?php
    $mem = new Memcache;
    $mem->connect("192.168.30.14", 11211) or die("Could not connect");
    $version = $mem->getVersion();
    echo "Server's version: ".$version."<br/>\n";
    $mem->set('hellokey', 'Hello World', 0, 600) or die("Failed to save data at the memcached server");
    echo "Store data in the cache (data will expire in 600 seconds)<br/>\n";
    $get_result = $mem->get('hellokey');
    echo "$get_result is from memcached server.";
?>

分布式缓存memcached_memcached_05


六、php程序调用memcached服务的另一个扩展memcached

    memcache扩展是原生的(基于pecl扩展库),而memcached扩展是基于libmemcached库开发的,libmemcached是memcache的C接口,具有低内存,线程安全等特点;memcached扩展支持Binary Protocol,而memcache扩展不支持;总之,memcached扩展相对来说具有更高的性能。

    libmemcached还提供了数个可以远程使用的memcached管理工具,如memcat, memping,memstat,memslap等。

    既然memcached扩展基于limemcached,因此要先编译安装libmemcached;libmemcached的源码包可到https://launchpad.net/libmemcached/+download获取,memcached扩展的源码包可到http://pecl.php.net/上获取;

    编译memcached扩展

      ./configure --with-libmemcached-dir=/path/to/somedir(指定libmemcached的安装目录) --enable-memcached

    其它步骤与安装memcache扩展类似,不再赘述


七、memcached的图形管理工具

   memcached的图形管理管理工具主要有memcachephpmemadmin-masterphpMemcachedAdmin

   phpMemcachedAdmin的压缩包可到http://blog.elijaa.org/phpmemcachedadmin-download-version-1-2-2/获取

[root@node1 scripts]# ls
index.php  memcachephp.zip  memtest.php
[root@node1 scripts]# unzip memcachephp.zip 
[root@node1 scripts]# ls
index.php  memcache.php  memcachephp.zip  memtest.php
[root@node1 scripts]# vim memcache.php 

<?php
...
$VERSION='$Id: memcache.php,v 1.1.2.3 2008/08/28 18:07:54 mikl Exp $';

define('ADMIN_USERNAME','hello');      // Admin Username   #设置一个账号和密码
define('ADMIN_PASSWORD','123');         // Admin Password
define('DATE_FORMAT','Y/m/d H:i:s');
define('GRAPH_SIZE',200);
define('MAX_ITEM_DUMP',50);

$MEMCACHE_SERVERS[] = '192.168.30.14:11211'; // add more as an array   #指定memcached服务器地址
...

分布式缓存memcached_数据_06


八、memcached的分布式

    memcached本身没有“分布式”的功能,memcached的分布式是由客户端实现的。memcached的客户端接口(API,函数库)用hash算法根据“键”来决定保存数据的memcached服务器。获取数据时把要获取的“键”传递给函数库,函数库通过与数据保存时相同的算法,根据“键”选择服务器。使用的算法相同,就能选中与保存时相同的服务器。这样,将不同的键保存到不同的服务器上,就实现了memcached的分布式。memcached服务器增多后,键就会分散,即使一台memcached服务器发生故障无法连接,也不会影响其他的缓存。

    为了减小增删节点对缓存的影响和增加缓存的平衡性,应尽量使用“一致性hash”算法,关于“一致性hash”算法,可参考http://blog.csdn.net/cywosp/article/details/23397179

  1、使用“一致性hash”算法做缓存分布示例

    ①启动若干个memcached服务器;这里为演示方便,仅在一个memcached服务主机上启动几个实例

[root@node4 ~]# memcached -d -u memcached -m 20 -p 11211
[root@node4 ~]# memcached -d -u memcached -m 20 -p 11212
[root@node4 ~]# memcached -d -u memcached -m 20 -p 11213
[root@node4 ~]# ss -tnl
State       Recv-Q Send-Q                   Local Address:Port                       Peer Address:Port 
LISTEN      0      128                      :::11211                                 :::*     
LISTEN      0      128                      *:11211                                  *:*     
LISTEN      0      128                      :::11212                                 :::*     
LISTEN      0      128                      *:11212                                  *:*     
LISTEN      0      128                      :::11213                                 :::*     
LISTEN      0      128                      *:11213                                  *:*
...

   ②修改php的memcache扩展源码包中的memcache.c文件中的算法设置,然后重新编译

      "memcache.hash_strategy",         "consistent"

       MEMCACHE_G(hash_strategy)        = MMC_CONSISTENT_HASH;

    当然,可不用修改源码重新编译,还有另外的设置方法,可参考http://wtm-mac.iteye.com/blog/1687746

[root@node1 ~]# tar xf memcache-2.2.7.tgz 
[root@node1 ~]# cd memcache-2.2.7
[root@node1 memcache-2.2.7]# vim memcache.c
...
"memcache.hash_strategy",         "consistent"
...
MEMCACHE_G(hash_strategy)        = MMC_CONSISTENT_HASH;
# 之后的编译安装的步骤略

   ③创建一个测试文件

       vim /web/scripts/distribute.php

[root@node1 ~]# vim /web/scripts/distribute.php 

$mem = new Memcache;
$mem->addServer('192.168.30.14', 11211);
$mem->addServer('192.168.30.14', 11212);
$mem->addServer('192.168.30.14', 11213);

$key1 = 'mdtest1';
$value1 = '1';
$mem->add($key1, $value1);

$key2 = 'mdtest2';
$value2 = '2';
$mem->add($key2, $value2);

$key3 = 'mdtest3';
$value3 = '3';
$mem->add($key3, $value3);

$key4 = 'mdtest4';
$value4 = '4';
$mem->add($key4, $value4);

$key5 = 'mdtest5';
$value5 = '5';
$mem->add($key5, $value5);

$key6 = 'mdtest6';
$value6 = '6';
$mem->add($key6, $value6);

echo "OK";
?>

2、利用magent搭建memcached集群

    magent是一个缓存代理服务器,可以连接多台后端Memcached服务器,它接受客户端的请求,根据一定的算法做缓存分布,而且还能对后端memcached缓存做高可用。具体的安装配置可参考http://www.php-note.com/article/detail/800


九、Nginx整合memcached

   nginx的memcached模块能够实现调用memcached服务进行缓存

   配置示例:

     server {

        listen       80;

        server_name  www.hello.com;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {

            set $memcached_key $uri?$args;   #表示将请求的URI作为查询的key

            memcached_pass   127.0.0.1:11211;

            default_type    text/html;

            error_page     404 @fallback;

        }

        location @fallback {

                proxy_pass http://172.16.0.1;

        }

      }

   memcached模块中的一些指令:

     memcached_pass address;

     memcached_buffer_size size;

     memcached_connect_timeout time;

     memcached_read_timeout time;

     memcached_send_timeout time;

     这些指令与proxy模块中的指令类似,其用法不再赘述,可查看官方文档