memcache高速缓存工作原理及应用

Memcached,是高性能的分布式内存缓存服务器,主要功能就是通过缓存数据库的查询,减少对数据库的访问次数,来提高动态web应用的速度和可扩展性。

memcached 是以守护程序方法运行于一个或多个服务器中,随时接受客户端的连接操作,客户端可以由各种语言编写,目前一致的客户端api包括 Perl / PHP / Python / Java / C# / C 等等。客户端在与 memcached 服务建立连接之后,接下来的事情就是存取对象了, 每个被存取的对象都有一个唯一的标识符 key,存取操作均通过这个 key进行,保存到 memcached 中的对象实际上是放置内存中的,并不是保存在平时的 cache 文件中的,这也是为什么 memcached 能够如此高效快速的原因。

注意,这些对象并不是持久的, 服务停止之后, 里边的数据就会丢失。

Memcached应用模型

Memcached的安装

准备

libevent

Libevent 是一个用C语言编写的、轻量级的开源高性能网络库。
主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。
Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomit、 Nylon、 Netchat等等。

wget http://n.sinaimg.cn/games/3ece443e/20160929/libevent-2.0.22-stable.tar
tar -vxf libevent-2.0.22-stable.tar
cd libevent-2.0.22-stable
./configure --prefix=/usr/local/libevent
make && make install

安装

wget http://n.sinaimg.cn/games/3ece443e/20160930/memcached-1.4.31.tar.gz
cd memcached-1.4.31
 ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
make && make install

查看是否已经安装成功

cd /usr/local/memcached/
ll
drwxr-xr-x 2 root root 4096 9月  28 10:56 bin
drwxr-xr-x 3 root root 4096 9月  28 10:56 include
drwxr-xr-x 3 root root 4096 9月  28 10:56 share

Memcached管理

启动

启动Memcached服务器

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

查看是否启动成功

ps aux | grep memcache
root     24428  0.0  0.0 323120   864 ?        Ssl  11:00   0:00 /usr/local/memcached/bin/memcached -d -m 128 -u root -p 11211
root     24436  0.0  0.0 112664   984 pts/0    D+   11:00   0:00 grep --color=auto memcache

netstat -tlun | grep 11211
tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN
tcp6       0      0 :::11211                :::*                    LISTEN
udp        0      0 0.0.0.0:11211           0.0.0.0:*
udp6       0      0 :::11211                :::*

设置开机自启动

echo "/usr/local/memcached/bin/memcached -d -m 128 -u root -p 11211" >> /etc/rc.d/rc.local

Memcached启动选项及说明

选项 描述
-p Memcached监听的TCP端口,要保证该端口号未被占用
-U 指定监听UDP的端口,默认11211,0表示关闭
-s 指定Memcached用于监听的UNIX socket文件
-A enable ascii “shutdown” command
-a 设置-s选项指定的UNIX socket文件的权限(默认权限: 0700)
-l 监听的服务器IP地址,如果有多个地址的话,使用逗号分隔,格式可以为“IP地址:端口号”,例如:-l 指定192.168.0.184:19830,192.168.0.195:13542;端口号也可以通过-p选项指定
-d 指定memcached进程作为一个守护进程启动
-r 设置产生core文件大小
-u 运行memcached的用户 (only when run as root)
-m 指定分配给memcached使用的内存,单位是MB(默认: 64 MB)
-M 当内存使用超出配置值时,禁止自动清除缓存中的数据项,此时Memcached不可用,直到内存被释放
-c 设置最大运行的并发连接数,默认是1024
-k 设置锁定所有分页的内存,对于大缓存应用场景,谨慎使用该选项
-v 输出警告和错误信息
-vv 打印信息比-v更详细:不仅输出警告和错误信息,也输出客户端请求和响应信息
-vvv extremely verbose (also print internal state transitions)
-h 显示Memcached版本和摘要信息
-i 打印libevent和Memcached的licenses信息
-V 输出Memcached版本号
-P 保存memcached进程的pid文件,(与 -d 一起搭配使用)
-f 用于计算缓存数据项的内存块大小的乘数因子,默认是1.25
-n 为缓存数据项的key、value、flag设置最小分配字节数,默认是48
-L 尝试使用大内存分页(pages)
-D 用于统计报告中Key前缀和ID之间的分隔符,默认是冒号“:”
-t 指定用来处理请求的线程数,默认为4
-R 为避免客户端饿死(starvation),对连续达到的客户端请求数设置一个限额,如果超过该设置,会选择另一个连接来处理请求,默认为20
-C 禁用CAS
-b Set the backlog queue limit (default: 1024)
-B 指定使用的协议,默认行为是自动协商(autonegotiate),可能使用的选项有auto、ascii、binary。
-I Override the size of each slab page. Adjusts max item size(default: 1mb, min: 1k, max: 128m)
-F 禁用flush_all命令
-o 指定逗号分隔的选项,一般用于用于扩展或实验性质的选项

通过telnet连接使用Memcache

连接

telnet 127.0.0.1 11211

命令格式: \r\n \r\n

可以是”set”, “add”, “replace”
客户端需要保存数据的key。
是一个16位的无符号的整数(以十进制的方式表示)。
过期的时间。
最后客户端需要加上”\r\n”作为”命令头”的结束标志。即回车

示例:

保存一个数据(保存一个『cache_key1=>12345』的键值对到memcached 60s)

set cache_key1 0 60 5
12345
STORED

获取刚保存的值

get cache_key1
VALUE cache_key1 0 5
12345
END

其他命令:

Command Description Example
get 获取值 get mykey
set 设置值(可以存在可以不存在) set mykey 0 60 5
add 添加新值 add newkey 0 60 5
replace 替换值(必须已存在) replace key 0 60 5
append 在原有值之后添加数据 append key 0 60 15
prepend 在原有值之前添加数据 prepend key 0 60 15
incr Increments numerical key value by given number incr mykey 2
decr Decrements numerical key value by given number decr mykey 5
delete 删除一条数据 delete mykey
flush_all 清除所有数据 flush_all
    |清除900秒之内的数据 | flush_all 900

stats | 查看所有状态| stats
| Prints memory statistics | stats slabs
| Prints memory statistics | stats malloc
| Print higher level allocation statistics | stats items
| | stats detail
| 已使用大小 | stats sizes
| 重置状态 | stats reset
version | 查看版本 | version
verbosity | Increases log level | verbosity
quit | 退出telnet连接 | quit

通过客户端(PHP)连接和使用Memcached

php扩展Memcached安装

依赖

libmemcached, 是一个 memcached 的库,客户端库,C 和 C++ 语言实现的客户端库,具有低内存占用率、线程安全、并提供对memcached功能的全面支持。它还采用 多种命令行工具: memcat , memflush , memrm , memstat ,并memslap (负载代)。程序库一直在设计,让不同的散列方法对密钥,分割的钥匙,并使用统一的散列分配。

wget https://launchpadlibrarian.net/165454254/libmemcached-1.0.18.tar.gz
tar -zxvf libmemcached-1.0.18.tar.gz
cd libmemcached-1.0.18
./configure --prefix=/usr/local/libmemcached
make && make install

安装扩展

wget http://n.sinaimg.cn/games/3ece443e/20160929/memcached-2.2.0.tar
tar -xvf memcached-2.2.0.tar
cd memcached-2.2.0
/usr/local/php56/bin/phpize
./configure --with-php-config=/usr/local/php56/bin/php-config --with-libmemcached-dir=/usr/local/libmemcached  --enable-memcached --disable-memcached-sasl
make && make install
Installing shared extensions:     /usr/local/php56/lib/php/extensions/no-debug-non-zts-20131226/

查看是否安装成功

cd /usr/local/php56/lib/php/extensions/no-debug-non-zts-20131226/
ll
-rwxr-xr-x 1 root root  380475 9月  28 22:25 memcached.so
-rwxr-xr-x 1 root root  756714 9月  26 17:32 mysqli.so
-rwxr-xr-x 1 root root 1333912 9月  24 23:31 opcache.a
-rwxr-xr-x 1 root root  618435 9月  24 23:31 opcache.so

修改配置

vi /usr/local/php56/lib/php.ini
extension=/usr/local/php56/lib/php/extensions/no-debug-non-zts-20131226/memcached.so

重启php-fpm

kill -USR2 `cat /usr/local/php56/var/run/php-fpm.pid`

查看是否已经加载成功

/usr/local/php56/bin/php -m
或通过phpinfo();查看

测试

vi memcache_test.php
<?php
        $mc = new Memcached();
        var_dump($mc);
        $mc->addServer('127.0.0.1', 11211);
        $mc->set('cache_key','mem_value',30);
        $val = $mc->get('cache_key');
        var_dump($val);
        var_dump($mc->delete('cache_key'));
        $mc->quit();

访问结果:

object(Memcached)#1 (0) { } string(9) "mem_value" bool(true)

php关于memcached 的两种扩展memcache 和 memcached 介绍

  1. 目前大多数php环境里使用的都是不带d的memcache版本,这个版本出的比较早,是一个原生版本,完全在php框架内开发的。与之对应的带d的memcached是建立在libmemcached的基础上,所以相对来说,memcached版本的功能更全一些。

    memcache:

    memcached:

  2. Memcache是原生实现的,支持OO和非OO两套接口并存。而memcached是使用libmemcached,只支持OO接口。

  3. memcached有了一个统一的setOption()来设置设置,而不用在操作的时候设置了。Memcached实现了更多的memcached协议。

  4. memcached支持Binary Protocol,而memcache不支持。这意味着memcached会有更高的性能。不过memcached目前还不支持长连接。

  5. 另外一点也是大家比较关心的,就是所使用的算法。“一致性hash算法”是当添加或删除存储节点时,对存储在memcached上的数据影响较小的一种算法。在php的两个扩展库中,都可以使用该算法,只是设置方法有所不同。

  • Memcache

修改php.ini添加:

[Memcache]
Memcache.allow_failover = 1
Memcache.hash_strategy =consistent
Memcache.hash_function =crc32

或在php中使用ini_set方法:

ini_set(‘memcache.hash_strategy','standard');
ini_set(‘memcache.hash_function','crc32');
  • Memcached
$mem = new memcached();
$mem->setOption(Memcached::OPT_DISTRIBUTION,Memcached::DISTRIBUTION_CONSISTENT);
$mem->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE,true);

Memcached监控

利用phpmemcache.php图形监控工具

下载 phpmemcache.php

wget http://n.sinaimg.cn/games/3ece443e/20160929/phpmemcache.php

将phpmemcache.php放入web目录

mv phpmemcache.php /usr/local/nginx/html

修改phpmemcache.php中配置

define('ADMIN_USERNAME','xxxx');    // 用户名修改,在访问 phpmemcache.php 需要进行认证
define('ADMIN_PASSWORD','xxxx');    // 密码
define('DATE_FORMAT','Y/m/d H:i:s');
define('GRAPH_SIZE',200);
define('MAX_ITEM_DUMP',50);

$MEMCACHE_SERVERS[] = '127.0.0.1:11211'; // 加入需要监控的memcached服务器
//$MEMCACHE_SERVERS[] = '192.168.200.104:11212'; // add more as an array

浏览器访问
phpmemcache浏览器访问效果

利用Stats命令查看

利用stats命令可以查看当前memcached的各种状态

telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
stats
STAT pid 24732
STAT uptime 66597
STAT time 1475115983
STAT version 1.4.31
STAT libevent 2.0.22-stable
STAT pointer_size 64
STAT rusage_user 6.194421
STAT rusage_system 2.419890
STAT curr_connections 10
STAT total_connections 16
STAT connection_structures 11
STAT reserved_fds 20
STAT cmd_get 5
STAT cmd_set 8
STAT cmd_flush 0
STAT cmd_touch 0
STAT get_hits 4
STAT get_misses 1
STAT get_expired 0
STAT get_flushed 0
STAT delete_misses 0
STAT delete_hits 2
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 3850
STAT bytes_written 293
STAT limit_maxbytes 134217728
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT time_in_listen_disabled_us 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT malloc_fails 0
STAT log_worker_dropped 0
STAT log_worker_written 0
STAT log_watcher_skipped 0
STAT log_watcher_sent 0
STAT bytes 0
STAT curr_items 0
STAT total_items 6
STAT expired_unfetched 0
STAT evicted_unfetched 0
STAT evictions 0
STAT reclaimed 2
STAT crawler_reclaimed 0
STAT crawler_items_checked 0
STAT lrutail_reflocked 0
END

Stats详解

选项 说明
pid memcache服务器的进程ID
uptime 服务器已经运行的秒数
time 服务器当前的unix时间戳
version memcache版本
pointer_size 当前操作系统的指针大小(32位系统一般是32bit)
rusage_user 进程的累计用户时间
rusage_system 进程的累计系统时间
curr_items 服务器当前存储的items数量
total_items 从服务器启动以后存储的items总数量
bytes 当前服务器存储items占用的字节数
curr_connections 当前打开着的连接数
total_connections 从服务器启动以后曾经打开过的连接数
connection_structures 服务器分配的连接构造数
cmd_get get命令(获取)总请求次数
cmd_set set命令(保存)总请求次数
get_hits 总命中次数
get_misses 总未命中次数
evictions 为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items)
bytes_read 总读取字节数(请求字节数)
bytes_written 总发送字节数(结果字节数)
limit_maxbytes 分配给memcache的内存大小(字节)
threads 当前线程数

利用各种监控软件查看(例如:nagios监控memcache的插件)

只以命中率大于和小于为例两种状态。

vim check_memcache
#!/bin/sh
if [ $# -ne 1 ]
then
echo "Usage:$0 -c num2"
exit 0
fi
cmd_get=`/usr/local/nagios/libexec/check_tcp -H localhost -p 11211 -E -s 'stats\r\nquit\r\n' -e 'uptime' |grep cmd_get | awk '&#123;print $3+0&#125;'`
get_hits=`/usr/local/nagios/libexec/check_tcp -H localhost -p 11211 -E -s 'stats\r\nquit\r\n' -e 'uptime' |grep get_hits | awk '&#123;print $3+0&#125;'`
hit_rate=`echo "$get_hits*100/$cmd_get"|bc`
if [ $hit_rate -gt $1 ];then
echo "OK - hit rate is $hit_rate | hit_rate=$hit_rate; cmd_get=$cmd_get; get_hits=$get_hits"
exit 0
else
echo "CRITICAL - hit rate is $hit_rate | hit_rate=$hit_rate; cmd_get=$cmd_get; get_hits=$get_hits"
exit 2
fi

测试命中率大于80%为正常为例;

eg:
sh check_memcache 80
root@ip-10-250-114-95:/liang# sh check_memcache 80
OK - hit rate is 99 | hit_rate=99; cmd_get=142547; get_hits=141880

以上证明命中率99%,即状态为OK.