如果一个网站流量很大,则查询数据库将会耗费大量时间。如果将经常查询的的数据和对象缓存到内存中,则需要查询数据库时,直接返回内存中缓存的数据。这中静态化方式则会高效很多。分布式缓存系统是为了解决数据库服务器和web服务器直接的瓶颈。其中memcached是一个开源、高性能、分布式的内存对象缓存系统。主要通过在内存中缓存数据和对象减轻数据库的负载来加速动态web程序。内存中缓存的数据通

过API的方式被存取,数据就像一张大的HASH表,以键-值对方式存在。


memcached原理详述及配置_原理



读取

执行读取操作的顺序是从 Web 层获取请求(需要执行一次数据库查询)并检查之前在缓存中存储的查询结果。如果我找到所需的值,则返回它。如果未找到,则执行查询并将结果存储在缓存中,然后再将结果返回给 Web 层。

写入

将数据写入到数据库中时,首先需要执行数据库写入操作,然后将之前缓存的任何受此写入操作影响的结果设定为无效。此过程有助于防止缓存和数据库之间出现数据不一致性。

 

Memcached采用client/server架构,服务端启动守护进程,等待clent请求到达,采用异步I/O,使用libevenet作为事件通知机制。可以建设多个服务端协同工作,但这些服务端之间并不通信,每个server端对自己的数据进行管理,客户端制定server端IP和端口进行通信。缓存在内存中的数据并不会同步到磁盘上,因此,重启后缓存的数据就会丢失。当缓存数据的总大小达到初始设置值时,就会使用LRU算法删除不用的缓存。



Memcached采用slaballocation机制分配和管理内存,其原理是将内存分割成各种尺寸的块chunk,Chunk就是用来存储key-value数据的最小单位,把尺寸相同的块分成组(slab class) ,每个slab class的大小可以在memcached启动时制定GrowethFactor控制,默认值为1.25。这些内存块不会释放,可重复利用。


可同过以下命令看到slab class生成过程:

#/usr/local/memcached/bin/memcached -d -f 1.25 -n 50 -vvv -u nobody
slabclass   1: chunk size       104 perslab   10082
slabclass   2: chunk size       136 perslab    7710
slabclass   3: chunk size       176 perslab    5957
slabclass   4: chunk size       224 perslab    4681
slabclass   5: chunk size       280 perslab    3744
slabclass   6: chunk size       352 perslab    2978
slabclass   7: chunk size       440 perslab    2383
slab class   8: chunk size       552 perslab    1899
slabclass   9: chunk size       696 perslab    1506
slabclass  10: chunk size       872 perslab    1202
slabclass  11: chunk size      1096 perslab     956
slabclass  12: chunk size      1376 perslab     762
slabclass  13: chunk size      1720 perslab     609
slabclass  14: chunk size      2152 perslab     487
slabclass  15: chunk size      2696 perslab     388
slabclass  16: chunk size      3376 perslab     310
slabclass  17: chunk size      4224 perslab     248
slabclass  18: chunk size      5280 perslab     198
slabclass  19: chunk size      6600 perslab     158
slabclass  20: chunk size      8256 perslab     127
slabclass  21: chunk size     10320 perslab     101
slabclass  22: chunk size     12904 perslab      81
slabclass  23: chunk size     16136 perslab      64
slabclass  24: chunk size     20176 perslab      51
slabclass  25: chunk size     25224 perslab      41
slabclass  26: chunk size     31536 perslab      33
slabclass  27: chunk size     39424 perslab      26
slabclass  28: chunk size     49280 perslab      21
slabclass  29: chunk size     61600 perslab      17
slabclass  30: chunk size     77000 perslab      13
slabclass  31: chunk size     96256 perslab      10
slabclass  32: chunk size    120320 perslab       8
slabclass  33: chunk size    150400 perslab       6
slabclass  34: chunk size    188000 perslab       5
slabclass  35: chunk size    235000 perslab       4
slabclass  36: chunk size    293752 perslab       3
slabclass  37: chunk size    367192 perslab       2
slabclass  38: chunk size    458992 perslab       2
slabclass  39: chunk size    573744 perslab       1
slabclass  40: chunk size    717184 perslab       1
slabclass  41: chunk size   1048576 perslab       1
<26server listening (auto-negotiate)
<27server listening (auto-negotiate)
<28send buffer was 124928, now 268435456
<32send buffer was 124928, now 268435456
<31server listening (udp)
<35server listening (udp)
<30server listening (udp)
<34server listening (udp)
<29server listening (udp)
<33server listening (udp)
<28server listening (udp)
<32server listening (udp)


Memcached常用选项说明

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

-d: daemon模式运行;

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

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

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

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

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

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

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

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

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

-S: 启用sasl进行用户认证;需要在编译时指定—enable-sasal

 


当Memcached接收到客户端发送过来的数据时首先会根据收到数据的大小选择一个最合适的Slab Class,然后通过查询Memcached保存着的该Slab Class内空闲Chunk的列表就可以找到一个可用于存储数据的Chunk。当一条数据库过期或者丢弃时,该记录所占用的Chunk就可以回收,重新添加到空闲列表中。从以上过程我们可以看出Memcached的内存管理制效率高,而且不会造成内存碎片,但是它最大的缺点就是会导致空间浪费。因为每个 Chunk都分配了特定长度的内存空间,所以变长数据无法充分利用这些空间。如图所示,将100个字节的数据缓存到128个字节的Chunk中,剩余的28个字节就浪费掉了。


memcached原理详述及配置_原理_02



安装libevent

Libevent是memcached所依赖的异步事件通知库,在安装memcached的之前需要安装它。

# cdlibevent-2.0.22-stable
# ./configure  –prefix=/usr/local/libevetn
# make 
# make install


 

# cd memcached-1.4.24
# ./configure--prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
# make 
# make install


 

为memcached体佛那个SysV风格服务启动脚本

# vim/etc/init.d/memcached

#!/bin/bash
#
# Init file formemcached
#
# chkconfig: - 86 14
# description:Distributed memory caching daemon
#
# processname:memcached
# config:/etc/sysconfig/memcached
 
./etc/rc.d/init.d/functions
#
## Default variables
PORT="11211"
USER="nobody"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""
 
RETVAL=0
prog="/usr/local/memcached/bin/memcached"
desc="Distributedmemory caching"
lockfile="/var/lock/subsys/memcached"
 
start() {
        echo -n $"Starting $desc(memcached): "
        daemon $prog -d -p $PORT -u $USER -c$MAXCONN -m $CACHESIZE "$OPTIONS"
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch$lockfile
        return $RETVAL
}
stop() {
        echo -n $"Shutting down $desc(memcached): "
        killproc $prog
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && rm -f$lockfile
        return $RETVAL
}
 
restart() {
        stop
        start
}
 
reload() {
        echo -n $"Reloading $desc ($prog):"
        killproc $prog -HUP
        RETVAL=$?
        echo
        return $RETVAL
}
 
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        restart
        ;;
condrestart)
        [ -e $lockfile ] && restart
        RETVAL=$?
        ;;
  reload)
        reload
        ;;
  status)
        status $prog
        RETVAL=$?
        ;;
   *)
        echo $"Usage: $0{start|stop|restart|condrestart|status}"
        RETVAL=1
esac
 
exit $RETVAL


# chmod +x/etc/init.d/memcached


基本 memcached 客户机命令

  set添加新的键值对,如果以存在,将会重写

    add当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。如果缓存中已经存在键,则之前的值将仍然保持相同,并且将            获得响应NOT_STORED

    replace仅当键已经存在时,replace 命令才会替换缓存中的键。如果缓存中不存在键,那么您将从 memcached 服务器接受到       一条 NOT_STORED 响应。

    get  命令用于检索与之前添加的键值对相关的值。

    gets 同get,但返回的信息要多余get

    delete用于删除 memcached 中的任何现有值。您将使用一个键调用 delete,如果该键存在于缓存中,则删除该值。如果不存           在,则返回一条 NOT_FOUND 消息。

    append 在一个存在的项后增加数据。

    prepend 在一个存在的项首增加数据

    stats 当前memcached实例信息

    flush_all 清理缓存中的所有键值对

    stats slabs显示slabs信息,可以获取每个slabs的chunksize长度,从而确定数据到底保存在哪个slab

    stats items 显示slab中item数目


修改命令语法:command <key><flags> <expiration time> <byte>

           <value>

key用于查找缓存值

flags可以包括键值对的×××参数,客户机使用它存储关于键值对的额外信息

expiration time缓存中保存键值对的时间,秒为单位,0表示永远

bytes缓存中存储的字节

value存储的值



# telnet localhost 11211
set xiaobai 0 0 3
123
STORED
add xiaobai 0 0 3
123    
NOT_STORED
get xiaobai
VALUE xiaobai 0 3
123
END
gets xiaobai
VALUE xiaobai 0 3 32
123
END
append xiaobai 0 0 3
456
STORED
get xiaobai
VALUE xiaobai 0 6
123456
END
prepend xiaobai 0 0 3
789
STORED
get xiaobai
VALUE xiaobai 0 9
789123456
END
delete xiaobai
DELETED
get xiaobai
END


安装memcached的php扩展

#cd memcache-2.2.7
# /usr/local/php/bin/phpize
#./configure --with-php-config=/usr/local/php/bin/php-config --enable-memcache
#make
#make install
安装完成后会提示
Installingshared extensions:     /usr/local/php/lib/php/extensions/no-debug-zts-20100525/


 

#mkdir /etc/php.d
#vim /etc/php.d/memcache.ini
     extension = /usr/local/php/lib/php/extensions/no-debug-zts-20100525/memcache.so
或vim /etc/php.ini
     extension =/usr/local/php/lib/php/extensions/no-debug-zts-20100525/memcache.so



测试PHP扩展是否安装成功

#vim /usr/html/test.php
<?php
$mem= new Memcache;
$mem->connect('127.0.0.1',11211);
$mem->set('test','Hello xiaoming',0,12);
$val= $mem->get('test');
echo$val;
?>