1.Memcached介绍

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。

Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信

2.Memcached的应用场景

2.1  作为数据库的前段缓存应用

1)完整缓存,静态缓存(易)

例如:商品分类,商品信息,将这些变动较少的(静态)数据提前存放到内存里,然后再对外提供服务。用户访问只读取memcached缓存,不读取数据库。

 

 

wKioL1f7Gs7h_Mf0AACH1RTKkNc610.png-wh_50


       2)热点缓存(难)

需要前端程序配合,将热点数据存放到内存中,用户访问这些数据,直接访问到memcached缓存。第一次访问非热点数据时,memcached缓存没有,就访问数据库,获取数据返回给客户端,同时在memcached中缓存一份,第二次访问相同内容时,就不在访问数据库,用Memcached缓存直接返回数据。

2.2  作为集群的session会话共享存储

以php的web网站集群为例,可以通过修改php.ini

[root@server_02 html]# egrep "session.save" /etc/php.ini|grep -v ";"      
session.save_handler = files
session.save_path = "/var/lib/php/session"

修改结果为:

session.save_handler = memcache                      --指定通过memcache进行缓存
session.save_path =  "tcp://192.168.1.112:11211"          --memcahced服务器的路径

2.3  memcached服务器的高可用方案

1) Memcached Repcached

一个单master单 slave的方案,但它的 master/slave都是可读写的,而且可以相互同步

2)memagent又名magent

每个magent节点又分别代理多个memcached服务节点,应用系统端使用magent pool来调用memcache进行存储。通过magent的连接池放的值会分别存在magent代理的所有memcached服务上去。

3)负载均衡器采用一直性哈希,将数据分散在若干个memcached服务器上

 

3.Memcached在业务中的工作流程

wKiom1f7Gynz60reAAbtT_mB77k758.png-wh_50 

4.Memcached服务分布式集群实现方法

特殊说明:Memcached的调度算法一般用一致性hash,提高缓存命中率,每台Memcached都是一部分数据

1.程序端实现

程序加载所有的memcached服务器,通过对key进行hash(一致性哈希)存放缓存。

2.负载均衡器实现

通过对key进行hash(一致性哈希)存放缓存

注:一致性hash不但可以保证每个对象只请求对应唯一的memcahced服务器,而且保证单台缓存服务器宕机,更新的缓存数据最少

5.Memcached服务特点及工作原理

wKioL1f7Gz2SjV7AAAPGdprgQ6s535.png-wh_50 

1.完全基于内存

2.节点之间相互独立

3.异步I/O模型,基于libevent模型的事件通知机制

4.缓存数据以key/value键值对形式存放

5.C/S模式架构,C语言编写,总共代码2000多行

6.数据存放在内存中,断电会丢失数据

7.缓存空间存放满之后,采用LRU算法删除过期缓存数据

 

6.Memcached内存管理机制

6.1 基本概念

1、slab class

在memcached中,对元素的管理是以slab为单元进行管理的。每个slab class对应一个或多个空间大小相同的chunk。参考下图一。

2、chunk

存放元素的最小单元。用户数据item(key、value等)最终会保存在chunk中。memcached会根据元素大小将其放到合适的slab class中。每一个slab class中的chunk空间大小是一样的,所以元素存放进来后,chunk可能会有部分空间剩余。参考下图二、下图三。

3、page

大小固定为1MB。当slab class空间不足时,就会申请page,并将page按chunk的大小进行切割。

wKioL1f7G1XDCNBPAACJ68TbOIw503.jpg-wh_50

图一  slab class逻辑结构图

wKiom1f7G2bSKaGHAABIq06VNds372.jpg-wh_50

图二  元素存入memcached会寻找最合适的slab class

wKiom1f7G56hO_GXAAAwbG25-DE383.jpg

图三 元素放入chunk时可能会有空间浪费

memcached使用自己的内存管理机制,可以有效避免系统内存碎片,避免给操作系统带来负担。

6.2 Memcached内存分配方式

启动memcached时,以-m指定大小的内存将会用于数据的存放。默认情况下,这些内存会被分隔成1M的page。每个page在必要时分配给slab class,然后根据slab class里chunk的大小,将page分隔成chunk。

一个page被赋给一个slab class后,它将不会再被移动。因为内存空间有限,如果在slab class 3中使用了较多的page,那么在slab class 4中就只能使用较少的page。可以这么认为,memcached是一个有很多更小的相互独立的缓存系统,每一个更小的缓存系统实际上就是slab class。每个slab class都有它自己的统计信息以及自己的LRU。

在启动memcached时,指定-vv参数,可以在启动日志中查看每个slab class的chunk大小。

[root@server_01 ~]# memcached  -vv -u root
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
slab class  11: chunk size       944 perslab    1110
slab class  12: chunk size      1184 perslab     885
slab class  13: chunk size      1480 perslab     708
slab class  14: chunk size      1856 perslab     564
slab class  15: chunk size      2320 perslab     451
slab class  16: chunk size      2904 perslab     361
slab class  17: chunk size      3632 perslab     288
slab class  18: chunk size      4544 perslab     230
slab class  19: chunk size      5680 perslab     184
slab class  20: chunk size      7104 perslab     147
slab class  21: chunk size      8880 perslab     118
slab class  22: chunk size     11104 perslab      94
slab class  23: chunk size     13880 perslab      75
slab class  24: chunk size     17352 perslab      60
slab class  25: chunk size     21696 perslab      48
slab class  26: chunk size     27120 perslab      38
slab class  27: chunk size     33904 perslab      30
slab class  28: chunk size     42384 perslab      24
slab class  29: chunk size     52984 perslab      19
slab class  30: chunk size     66232 perslab      15
slab class  31: chunk size     82792 perslab      12
slab class  32: chunk size    103496 perslab      10
slab class  33: chunk size    129376 perslab       8
slab class  34: chunk size    161720 perslab       6
slab class  35: chunk size    202152 perslab       5
slab class  36: chunk size    252696 perslab       4
slab class  37: chunk size    315872 perslab       3
slab class  38: chunk size    394840 perslab       2
slab class  39: chunk size    493552 perslab       2
slab class  40: chunk size    616944 perslab       1
slab class  41: chunk size    771184 perslab       1
slab class  42: chunk size   1048576 perslab       1

在slab class 1中,每个chunk大小为96字节,每个页面包含10922chunk(或item)。这两个数相乘,应该最近接1个page的大小(默认是1MB)。

当存储元素时,它们将被放到最合适的slab class中。例如,50字节的元素(包含key、value等信息)将被存放到slab class 1中的chunk,根据之前的说明,此chunk中将会有30字节的空间浪费。如果存放数据总共有90字节,将被存放到slab class 2中,此时会有14字节的空间浪费。

6.3 Memcached优化

Memcached启动时,通过设置参数-f,可以设置每个slab class下chunk的空间增长率。尽量使每个chunk的size接近具体业务的size,减少内存空间浪费,提高内存利用率

6.4 Memcached内存回收

与redis不同的是,memcached不会主动回收内存。memcached会重复使用失效数据的内存。

如果获取了一个已失效的数据,memcached将会释放内存。后续再将新的数据存放进来时,将会重用此内存。

根据LRU(最近最少使用)算法,元素将被踢出以让给新的元素,或发现有过期的元素,它们的内存将被重用。如果元素还没有失效(失效日期为0或者将会在将来失效),slab class已经用完了所有空闲的chunk,并且没有空闲的page可以分配给此slab class,此时将会执行LRU算法踢出数据

6.5 LRU算法

当存放新的元素时,内存也可能会被回收。如果在相应的slab class里,既没有空闲的chunk,也没有空闲的page,memcached将会使用LRU算法查找应该被回收的元素。它将会查找LRU列表中尾部(最近最少使用)的一些元素,看它们是否已经失效,如果存在失效的元素,则将此元素占用的空间重用。如果找不到失效的元素,那么将踢出最尾部还没有失效的元素。

 

7.Memcached安装配置

1)安装libevent(前提)

yum install libevent libevent-devle -y

也可以通过编译安装libevent包

2)安装Memcached服务端

说明:Memcached是服务端

      Memcache是客户端

[root@server tools]# wget http://memcached.org/files/memcached-1.4.31.tar.gz
[root@server_02 tools]# tar xf memcached-1.4.31.tar.gz 
[root@server_02 tools]# cd memcached-1.4.31
[root@server_02 memcached-1.4.31]# ./configure 
[root@server_02 memcached-1.4.31]# make && make install

3)启动memcached服务

[root@server_02 memcached-1.4.31]# memcached -d -m 10m -u root -l 192.168.1.112 -p 11211-c 256 -P /tmp/memcached.pid
[root@server_02 memcached-1.4.31]# ss -lntup|grep memcached
udp    UNCONN     0      0          192.168.1.112:11211                *:*      users:(("memcached",833,27),("memcached",833,28),("memcached",833,29),("memcached",833,30))
tcp    LISTEN     0      128        192.168.1.112:11211                 *:*      users:(("memcached",833,26))
[root@server_02 memcached-1.4.31]#

 

-d选项是以一个守护进程启动,
-m是分配给Memcache使用的内存数量,单位是MB,我这里是10MB
-u是运行Memcache的用户,我这里是root
-l是监听的服务器IP地址,如果有多个地址的话,我这里指定了服务器的IP地址192.168.1.112
-p是设置Memcache监听的端口,最好是1024以上的端口,默认是11211
-c选项是最大运行的并发连接数,默认是1024,我这里设置了256,按照你服务器的负载量来设定,
-P是设置保存Memcachepid文件,我这里是保存在 /tmp/memcached.pid

注意:可以通过更改端口号,实现启动多个memcached实例

4)关闭memcached服务

   1.pkill memcached

   2.kill  `cat /tmp/memcached.pid`

5) memcached存储数据测试(nc/telnet测试)

[root@server_02 memcached-1.4.31]# telnet 192.168.1.112 11211
Trying 192.168.1.112...
Connected to 192.168.1.112.
Escape character is '^]'.
set key key2 0 0 4
CLIENT_ERROR bad command line format
 
set key1 0 60 4
youd
STORED
get key1
VALUE key1 0 4
youd
END
delete key1
DELETED
get key1
END

命令说明:

<command name> <key> <flags> <exptime> <bytes>\r\n <data block>\r\n
a) <command name> 可以是”setaddreplace
set”表示按照相应的<key>存储该数据,没有的时候增加,有的覆盖。
add”表示按照相应的<key>添加该数据,但是如果该<key>已经存在则会操作失败。
replace”表示按照相应的<key>替换数据,但是如果该<key>不存在则操作失败

b) <key> 客户端需要保存数据的key

c) <flags> 是一个16位的无符号的整数(以十进制的方式表示)
该标志将和需要存储的数据一起存储,并在客户端get数据时返回。
客户可以将此标志用做特殊用途,此标志对服务器来说是不透明的。

d) <exptime> 过期的时间。
若为0表示存储的数据永远不过时(但可被服务器算法:LRU 等替换)
如果非0(unix时间或者距离此时的秒数),当过期后,服务器可以保证用户得不到该数据(以服务器时间为标准)

e) <bytes> 需要存储的字节数(不包含最后的”\r\n),当用户希望存储空数据时,<bytes>可以为0

f) 最后客户端需要加上”\r\n”作为”命令头”的结束标志。
<data block>\r\n

紧接着”命令头”结束之后就要发送数据块(即希望存储的数据内容),最后加上”\r\n”作为此次通讯的结束。

linux nc命令操作memcache方法实例
1)存储数据:printf “set key 0 10 6\r\nresult\r\n” |nc 192.168.1.112 11211
2)获取数据:printf “get key\r\n” |nc 192.168.1.112 11211
3)删除数据:printf “delete key\r\n” |nc 192.168.1.112 11211
4)查看状态:printf “stats\r\n” |nc 192.168.1.112 11211
5)模拟top命令查看状态:watch “echo stats” |nc 192.168.1.112 11211

6)清空缓存:printf “flush_all\r\n” |nc 192.168.1.112 11211 (小心操作,清空了缓存就没了

 

6)php安装memcache客户端(扩展memcache模块)

参考:http://php.net/manual/zh/memcache.installation.php

tar xf memcache-3.0.6.tgz 
cd memcache-3.0.6
phpize
./configure --enable-memcache --with-php-config=/usr/bin/php-config --with-zlib-dir
make && make install

安装成功后,修改php.ini文件的一下两项内容:

[root@server_02 html]# egrep "memcache.so|extension" /etc/php.ini|grep -v ";"

extension_dir = "/usr/lib64/php/modules/"         ---扩展模块的目录

extension = memcache.so                         - --扩展的模块名称

 

用phpinfo查看下memcache是否加载成功

wKiom1f7G-3R37YFAABGT0H79Ck903.png-wh_50 

7)php程序测试memcached

php测试页面代码:

[root@server_02 html]# vim memcache.php
<?php
$memcache = new Memcache;
$memcache->connect('192.168.1.112', 11211);
$memcache->set('test', 'successs'); 
echo $memcache->get('test');      
?>

将以上代码,放到memcache.php文件中,将memcache.php文件放到web服务目录下/var/www/html

php页面显示内容:

wKioL1f7HAWSOqKUAAAg8reVlU8752.png-wh_50 

 

 

 

8.memcached服务的web管理工具memadmin

wget http://www.junopen.com/memadmin/memadmin-1.0.12.tar.gz
tar xf memadmin-1.0.12.tar.gz
mv ./memadmin /var/www/html/memadmin   --将memadmin目录移动到web服务器目录下

memadmin默认账号密码都是:admin

memadmin网页效果图:

wKiom1f7HCSSwWfKAACCqzXrFPg438.png-wh_50 

常见问题:

1.如果启动Memcached服务的时候遇到了

/usr/local/bin/memcached: error while loading shared libraries: libevent-1.2.so.1: cannot open shared object file: No such file or directory;

解决方案:

[root@localhost bin]# LD_DEBUG=libs memcached -v 
[root@localhost bin]# ln -s /usr/lib/libevent-1.2.so.1 /usr/lib64/libevent-1.2.so.1
[root@localhost bin]# /usr/local/bin/memcached -d -m 100 -u root -p 11211 -c 1000 -P /tmp/memcached.pid
[root@localhost bin]# ps -aux

可以看到启动的Memcached服务了.

 

2.Memcached服务加载到Linux的启动项中.万一机器断电系统重启.那么Memcached就会自动启动了.

假如启动Memcache的服务器端的命令为:
# /usr/local/bin/memcached -d -m 10 -u root -l 192.168.1.112 -p 11211 -c 256 -P /tmp/memcached.pid容来自17jquery

想开机自动启动的话,只需在/etc/rc.d/rc.local中加入一行,下面命令
/usr/local/memcached/bin/memcached -d -m 10 -p 12000 -u apache -c 256 
上面有些东西可以参考一下:即,ip不指定时,默认是本机,用户:最好选择是:apache 或 deamon