Memcached:高性能分佈式對象緩存系統

1 Memcached簡介


1. Memcached是高性能分佈式對象緩存系統,官方主頁http://memcached.org/,主頁上對它的介紹是:爲來自數據庫調用、API調用、或者頁面渲染的結果的小塊任意數據(字符串、對象)的一個內存中的鍵值存儲。

許多Web應用都將數據保存到RDBMS中,應用服務器從中讀取數據並在瀏覽器中顯示。但隨着數據量的增大、訪問的集中,就會出現RDBMS的負擔加重、數據庫響應惡化、網站顯示延遲等重大影響。

這時就該memcached大顯身手了。memcached是高性能的分佈式內存緩存服務器。一般的使用目的是,通過緩存數據庫查詢結果,減少數據庫訪問次數,以提高動態Web應用的速度、提高可擴展性。


2. Memcached的基本工作原理

如下爲memcached的工作流程示意圖,

wKiom1NDVfiwK4O1AAEWf3sN1Q8388.jpg

首次訪問:從RDBMS中取得數據保存在memcached;

第二次後:從memcached中取得數據顯示頁面。類似squid在web網頁緩存中的作用。


3. Memcached的特徵

memcached作爲高速運行的分佈式緩存服務器,具有以下的特點。

  • 協議簡單

    memcached的服務器客戶端通信並不使用複雜的XML等格式,而使用簡單的基於文本行的協議。因此,通過telnet也能在memcached上保存數據、取得數據。


  • 基於libevent的事件處理

    libevent是個程序庫,它將Linux的epoll、BSD類操作系統的kqueue等事件處理功能封裝成統一的接口。即使對服務器的連接數增加,也能發揮O(1)的性能。memcached使用這個libevent庫,因此能在Linux、BSD、Solaris等操作系統上發揮其高性能。


  • 內置內存存儲方式

    爲了提高性能,memcached中保存的數據都存儲在memcached內置的內存存儲空間中。由於數據僅存在於內存中,因此重啓memcached、重啓操作系統會導致全部數據消失。另外,內容容量達到指定值之後,就基於LRU(Least Recently Used)算法自動刪除不使用的緩存。memcached本身是爲緩存而設計的服務器,因此並沒有過多考慮數據的永久性問題。


  • memcached互不通信的分佈式

    memcached儘管是“分佈式”緩存服務器,但服務器端並沒有分佈式功能。各個memcached不會互相通信以共享信息。分佈式的實現取決於客戶端。如下爲memcached分佈式實現示意圖,

wKioL1NDVyjAgZfAAAClK5lQWd4468.jpg



4. 緩存與數據庫的同步

比較保險的做法是:查詢的時候(讀)從緩存中取,add、updae、delete的時候(寫)同時操作緩存與DB。

當然你也可以定時同步緩存與DB的數據,不同的業務應該有不同的選擇。


2 Memcached安裝、啓動


2.1 安裝前準備

memcached依賴於libevent庫,在安裝前需保證libevent庫已經安裝

yum install libevent libevent-devel


2.2 安裝

可以從官網下載到最新版本的memcached,直接下載請戳http://www.memcached.org/files/memcached-1.4.17.tar.gz,解壓、編譯安裝:

tar zxvf memcached-1.4.17.tar.gz ; cd memcached-1.4.17

./configure --prefix=/usr/local/memcached

make

make install


2.3 啓動

啓動前防火牆設置:關閉iptables或者添加以下內容到iptables中:

-A INPUT -m state NEW -m tcp -p tcp --dport 11211 -j ACCEPT

-A INPUT -m state NEW -m udp -p udp --dport 11211 -j ACCEPT


/usr/local/memcached/bin/memcached -u root -p 11211 -m 512m -vv

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


memcached常用參數說明:

-d:啓動一個守護進程.
-m:分配給Memcache使用的內存數量,單位是MB
-u:運行Memcache的用戶
-l:監聽的服務器IP地址
-p:設置Memcache監聽的端口,默認爲11211
-c:最大運行的併發連接數,默認是1024,可按照服務器的負載量來設定.
-P:設置保存Memcache的pid文件

-vv:詳細的輸出信息顯示


2.4 製作memcached啓動腳本

cat memcached.sh:

#!/bin/bash
# Description: start|stop|restart the Memcached services.
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
. /etc/rc.d/init.d/functions

memcached="/usr/local/bin/memcached"
[ -e $memcached ] || exit 1

start()
{
   echo "Start memcached:"
   daemon $memcached -d -m 521m -u root -l localhost -p 11211 -c 1500 -P /tmp/memcached.pid
}

stop()
{
   echo "Stop memcached:"
   #kill -9 `ps aux | grep memcached | awk '{print $2}'`
   killproc memcached
}

case "$1" in
   start)
       start
       ;;
   stop)
       stop
       ;;
   restart)
       stop
       sleep 3
       start
       ;;
   *)
       echo $"Usage: $0 {start|stop|restart}"
       exit 1
esac
exit $?

添加可執行權限:chmod +x memcached.sh

拷貝到/etc/rc.d/init.d/目錄下:cp memcached.sh /etc/rc.d/init.d/memcached

將memcached加入系統啓動項:

chkconfig  --add memcached

chkconfig --level 35 memcached on

啓動memcached:/etc/init.d/memcached start

Start memcached:
                                                                                                  [  OK  ]

查看memcached是否啓動:ps aux | grep memcached


3 Memcached分佈式集羣實現


由於Memcached本身沒有內置分佈式功能,多個memcached之間互不通信,導致無法實現使用多臺Memcache服務器來存儲不同的數據,最大程度的使用相同的資源;無法同步數據,容易造成單點故障。如果需要實現高可用性,需要通過其他的代理或者客戶端來實現:


3.1 使用magent來實現Memcached集羣


1. magent是一款簡單且有效的memcached服務器代理軟件,項目主頁請戳http://code.google.com/p/memagent/


2. magent的特徵

  • 能夠保持與memcached服務器的連接

  • 支持以下的memcached命令:

    get gets
    delete
    incr decr
    add set replace prepebd append
    cas
  • 基於libevent庫的事件驅動機制
  • 支持ketama算法
  • 備份服務器工廠
  • unix域socket


3. magent編譯安裝

mkdir magent && cd magent/

wget http://memagent.googlecode.com/files/magent-0.6.tar.gz

tar zxvf magent-0.6.tar.gz
/sbin/ldconfig
sed -i "s#LIBS = -levent#LIBS = -levent -lm#g" Makefile
make
cp magent /usr/bin/magent
cd ../


註解:編譯的時候可能報錯:

gcc -Wall -g -O2 -I/usr/local/include  -c -o magent.o magent.c
magent.c: In function ‘writev_list’:
magent.c:729: error: ‘SSIZE_MAX’ undeclared (first use in this function)
magent.c:729: error: (Each undeclared identifier is reported only once
magent.c:729: error: for each function it appears in.)
make: *** [magent.o] Error 1

出錯原因是在Linux系統上,SSIZE_MAX是定義在limits.h文件中,需要加入“#include <limits.h>”到magent.c中


4. magent命令參數說明:

magent  命令參數說明:
-h this message  
-u uid  
-g gid  
-p port, default is 11211. (0 to disable tcp support)  
-s ip:port, set memcached server ip and port  
-b ip:port, set backup memcached server ip and port  
-l ip, local bind ip address, default is 0.0.0.0  
-n number, set max connections, default is 4096  
-D do not go to background  
-k use ketama key allocation algorithm  
-f file, unix socket path to listen on. default is off  
-i number, max keep alive connections for one memcached server, default is20  
-v verbose  


5. 集羣實例測試

memcached -m 1 -u root -d -l 127.0.0.1 -p 11211
memcached -m 1 -u root -d -l 127.0.0.1 -p 11212
memcached -m 1 -u root -d -l 127.0.0.1 -p 11213
magent -u root -n 51200 -l 127.0.0.1 -p 12000 -s 127.0.0.1:11211 -s 127.0.0.1:11212 -b 127.0.0.1:11213

註解:

1、分別在11211、11212、11213端口啓動3個Memcached進程,在12000端口開啓magent代理程序;


2、11211、11212端口爲主Memcached,11213端口爲備份Memcached;


3、連接上12000的magent,set key1和set key2,根據哈希算法,key1被寫入11212和11213端口的Memcached,key2被寫入11212和11213端口的Memcached;


4、當11211、11212端口的Memcached死掉,連接到12000端口的magent取數據,數據會從11213端口的Memcached取出;


5、當11211、11212端口的Memcached重啓復活,連接到12000端口,magent會從11211或11212端口的Memcached取數據,由於這兩臺Memcached重啓後無數據,因此magent取得的將是空值,儘管11213端口的Memcached還有數據。可採用定時維護服務器,恢復memcached。


6、memcached和magent可以採用混合的方式來實現分佈式集羣,如下爲模型圖,

wKioL1NDZOXDR7-NAACaEZJI_iU660.jpg



6. 測試流程

[root@rango ~]# telnet 127.0.0.1 12000
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
stats
memcached agent v0.4
matrix 1 -> 127.0.0.1:11211, pool size 0
matrix 2 -> 127.0.0.1:11212, pool size 0
END
set key1 0 0 8
rangochen
STORED
set key2 0 0 8
rangochen
STORED
quit
Connection closed by foreign host.


[root@rango ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get key1
END
get key2
VALUE key2 0 8
rangochen
END
quit
Connection closed by foreign host.


[root@rango ~]# telnet 127.0.0.1 11212
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get key1
VALUE key1 0 8
rangochen
END
get key2
END
quit
Connection closed by foreign host.


[root@rango ~]# telnet 127.0.0.1 11213
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get key1
VALUE key1 0 8
rangochen
END
get key2
VALUE key2 0 8
rangochen
END
quit
Connection closed by foreign host.


模擬11211、11212端口的Memcached死掉
[root@rango ~]# ps -ef | grep memcached
root      6589     1  0 01:25 ?        00:00:00 memcached -m 1 -u root -d -l 127.0.0.1 -p 11211
root      6591     1  0 01:25 ?        00:00:00 memcached -m 1 -u root -d -l 127.0.0.1 -p 11212
root      6593     1  0 01:25 ?        00:00:00 memcached -m 1 -u root -d -l 127.0.0.1 -p 11213
root      6609  6509  0 01:44 pts/0    00:00:00 grep memcached
[root@rango ~]# kill -9 6589
[root@rango ~]# kill -9 6591
[root@rango ~]# telnet 127.0.0.1 12000
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get key1
VALUE key1 0 8
rangochen
END
get key2
VALUE key2 0 8
rangochen
END
quit
Connection closed by foreign host.


模擬11211、11212端口的Memcached重啓復活
[root@rango ~]# memcached -m 1 -u root -d -l 127.0.0.1 -p 11211
[root@rango ~]# memcached -m 1 -u root -d -l 127.0.0.1 -p 11212
[root@rango ~]# telnet 127.0.0.1 12000
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get key1
END
get key2
END
quit
Connection closed by foreign host.


3.2 java客戶端


3.2.1 XMemcached是一個基於Java nio的memcached客戶端。它線程安全,結構簡單,支持所有的memcached文本協議和二進制協議,並且有比較優異的性能表現。它還支持一些高級特性,如JMX、動態增刪節點、客戶端統計以及nio連接池等。


3.2.2 與同是基於java nio的spymemcached相比來說,XMemcached具有以下特點:
1)API模型是同步,異步的API使用比較繁瑣,在memcached協議加入noreply後,異步模型的存在價值就更可疑了;      
2)支持設置memcached的節點權重;      
3)支持動態增刪節點,可以通過編程或者JMX;      
4)支持nio連接池,並且允許讓用戶對網絡層面有更多的控制,提供更多的性能優化選項;      
5)支持客戶端數據統計;      
6)支持Kestrel,Kestrel是一個scala編寫的MQ server。


3.2.3 簡單實例
MemcachedClient client;
   try {
    client = new XMemcachedClient("localhost",11211);//默認端口
    // store a value for one hour(synchronously).
    String someObject = "緩存這個一個小時可以嗎?";
    client.set("key", 3600, someObject);

    // Retrieve a value.(synchronously).
    Object getSomeObject = client.get("key");
    // delete
    client.delete("key");
    System.out.println(getSomeObject.toString());
   } catch (TimeoutException e) {
    e.printStackTrace();
   } catch (InterruptedException e) {
    e.printStackTrace();
   } catch (MemcachedException e) {
    e.printStackTrace();
   } catch (IOException e) {
    e.printStackTrace();
   }
以上代碼是沒有經過Spring管理的,XMemcachedClient是一個常駐程序。所以可以考慮將它置入到Spring中,配置方式前面已講過。
使用方式見下:
private MemcachedClient memcachedClient;

public void setMemcachedClient(MemcachedClient memcachedClient) {
   this.memcachedClient = memcachedClient;
}
注入後直接可使用。


4 Memcached監控


Memcached的監控方式有多種,對應單機和分佈式集羣配置:


4.1 使用memcache.php來監控memcached


這是一種非常方便、快捷的memcached監控方式,下載該文件請戳http://livebookmark.net/memcachephp/memcachephp.zip

下載完後將該文件移動到網頁存放目錄即可,如/var/www/html/(apache)。在使用之前需要設置登錄賬戶、密碼等配置信息:vim memcache.php:

......

define('ADMIN_USERNAME','memcache');    // Admin Username
define('ADMIN_PASSWORD','131415');      // Admin Password

......

$MEMCACHE_SERVERS[] = '192.168.56.1:11211'; // 添加要監控的memcached服務器ip及端口
$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; //集羣環境下添加多個ip及端口


登錄http://ip/memcache.php ,查看相應的監控信息。


4.2 使用Nagios的memcached監控插件來實現


1. 可從以下地址下載該插件,請戳 http://cpan.uwinnipeg.ca/cpan/authors/id/Z/ZI/ZIGOROU/Nagios-Plugins-Memcached-0.02.tar.gz


2. 需要保證系統安裝有perl環境:

#rpm -q perl

perl-5.10.1-136.el6.i686

#which perl

/usr/bin/perl


3. 編譯安裝:

#tar zxvf Nagios-Plugins-Memcached-0.02.tar.gz ; cd Nagios-Plugins-Memcached-0.02

#cat README:

......

INSTALLATION

To install this module, run the following commands:

   perl Makefile.PL
   make
   make test
   make install

......

#perl Makefile.PL

報錯:Can't locate CPAN.pm in @INC (@INC contains: inc /usr/local/lib/perl5 /usr/local/share/perl5 /usr/lib/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib/perl5 /usr/share/perl5 .) at inc/Module/AutoInstall.pm line 635, <STDIN> line 1.

原因是沒有安裝相應的perl的CPAN模塊,解決:yum install perl-CPAN


#make

編譯。會下載一些編譯所需要的文件。


#make install

安裝。從輸出信息中可以知道,默認會將check_memcached安裝到/usr/bin目錄下,將該文件拷貝到Nagios的libexec目錄下:cp /usr/bin/check_memcached /usr/local/nagios/libexec/


測試check_memcached:/usr/local/nagios/libexec/check_memcached -h

報以下錯誤:Base class package "Nagios::Plugin" is empty.
   (Perhaps you need to 'use' the module which defines that package first,
   or make that module available in @INC (@INC contains: /usr/local/nagios/libexec/../lib /usr/local/lib/perl5 /usr/local/share/perl5 /usr/lib/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib/perl5 /usr/share/perl5 .).
at /usr/local/share/perl5/Nagios/Plugins/Memcached.pm line 6
BEGIN failed--compilation aborted at /usr/local/share/perl5/Nagios/Plugins/Memcached.pm line 6.
Compilation failed in require at /usr/local/nagios/libexec/check_memcached line 12.
BEGIN failed--compilation aborted at /usr/local/nagios/libexec/check_memcached line 12.

原因是缺少perl的nagios模塊:yum search perl-nagios

Loading mirror speeds from cached hostfile
* epel: mirrors.hust.edu.cn
* rpmforge: mirrors.neusoft.edu.cn
======================== N/S Matched: perl-nagios =========================
perl-Nagios-NSCA.noarch : Nagios::NSCA Perl module
perl-Nagios-Object.noarch : Nagios::Object - Nagios object configuration
                         : parsing
perl-Nagios-Plugin.noarch : Family of perl modules to streamline writing
                         : Nagios
perl-Nagios-Plugin-WWW-Mechanize.noarch : Login to a web page as a user and
                                       : get data as a Nagios plugin

 Name and summary matches only, use "search all" for everything.

安裝perl-Nagios-Plugin.noarch:yum install perl-Nagios-Plugin.noarch

再執行測試,報以下錯誤:

Can't locate Carp/Clan.pm in @INC (@INC contains: /usr/local/nagios/libexec/../lib /usr/local/lib/perl5 /usr/local/share/perl5 /usr/lib/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib/perl5 /usr/share/perl5 .) at /usr/local/share/perl5/Nagios/Plugins/Memcached.pm line 8.
BEGIN failed--compilation aborted at /usr/local/share/perl5/Nagios/Plugins/Memcached.pm line 8.
Compilation failed in require at /usr/local/nagios/libexec/check_memcached line 12.
BEGIN failed--compilation aborted at /usr/local/nagios/libexec/check_memcached line 12.

原因是沒有安裝perl的carp:clan包,安裝:yum install perl-Carp-Clan.noarch

最後安裝cache:memcached模塊:yum install perl-Cache-Memcached.noarch

執行:/usr/local/nagios/libexec/check_memcached -h

check_memcached 0.02 [http://search.cpan.org/dist/Nagios-Plugins-Memcached/bin/check_memcache]

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

Usage: check_memcached [-H host] [-w warnings] [-c critical] [--size-warnng size-warnng] [--size-critical size-critical] [--hit-warning hit-warning] [--hit-critical hit-critical] [-t timeout] [-v] [-h] [-?] [-V] [--extra-opts section@config_file]

......


4. 配置Nagios:

4.1 修改commands.cfg文件,添加監控命令定義:vim /usr/local/nagios/etc/objects/commands.cfg

#check response time(msec) for memcached
define command {
       command_name    check_memcached_response_11211
       command_line    /usr/local/bin/check_memcached -H 192.168.56.1 -w 300 -c 500
       }
#check cache size ratio(bytes/limit_maxbytes[%]) for memcached
define command {
       command_name    check_memcached_11211
       command_line    $USER1$/check_memcached -H 192.168.56.1:11211 --size-warning 80 --size-critical 90
       }
#check cache hit ratio(get_hits/cmd_get[%]) for memcached
define command {
       command_name    check_memcached_hit

       command_line    /usr/local/bin/check_memcached -H 192.168.56.1 --hit-warning 10 --size-critical 5
       }

註解:以上三個命令分別爲:監控memcached是否有響應、監控memcached的內存使用比例 、監控memcached的擊中率。


4.2 添加主機和服務:vim /usr/local/nagios/etc/objects/memcached.cfg

define host{
       use             linux-server
       host_name       memcache
       alias           Memcache_server
       address         192.168.56.1
       }

define service{
       use             generic-service
       host_name       memcache
       service_description     Memcached_response
       check_command   check_memcached_response_11211
       }

define service{
       use             generic-service
       host_name       memcache
       service_description     Memcached_size
       check_command   check_memcached_11211
       }
define service{
       use     generic-service
       host_name       memcache

       service_description     Memcached_hit
       check_command   check_memcached_hit
       }


4.3 將memcached.cfg添加到Nagios主配置文件中:

cfg_file=/usr/local/nagios/etc/objects/memcached.cfg


4.4 檢查Nagios配置是否有誤:/usr/local/nagios/bin/nagios -v /usr/local/nagios/etc/nagios.cfg


4.5 重啓Nagios,並登錄Nagios web監控界面查看:

/etc/init.d/nagios restart

登錄:http://localhost/nagios


4.3 使用MemAdmin監控管理工具來實現


MemAdmin是一款基於 PHP5 & JQuery、 可視化的Memcached管理與監控工具,使用PHP開發,體積小,操作簡單。主頁請戳http://www.junopen.com/memadmin/


主要功能:

  • 服務器參數監控:STATS、SETTINGS、ITEMS、SLABS、SIZES實時刷新

  • 服務器性能監控:GET、DELETE、INCR、DECR、CAS等常用操作命中率實時監控

  • 支持數據遍歷,方便對存儲內容進行監視

  • 支持條件查詢,篩選出滿足條件的KEY或VALUE

  • 數組、JSON等序列化字符反序列顯示

  • 兼容memcache協議的其他服務,如Tokyo Tyrant (遍歷功能除外)

  • 支持服務器連接池,多服務器管理切換方便簡潔

具體配置安裝和使用不再贅述,可自行查看相關文檔,lol


5 總結


本文就Memcached原理、安裝、分佈式安裝和監控等一一較爲詳細的介紹,關於高階的Memcached內部實現原理,還有待研究和學習。

                                                                                               ——Rango Chen


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章