1. 程式人生 > >Memcached高性能內存對象緩存系統

Memcached高性能內存對象緩存系統

ror 提高 理論 接收 新建 sta 成對 dep 方案

一、Memcached概述
  • Memcached 是一個高性能的分布式內存對象緩存系統,用於動態Web應用以減輕數據庫負載。它通過在內存中緩存數據和對象來減少讀取數據庫的次數,從而提高動態、數據庫驅動網站的速度。Memcached基於一個存儲鍵/值對的hashmap。其守護進程(daemon )是用C寫的,但是客戶端可以用任何語言來編寫,並通過memcached協議與守護進程通信。
  • 傳統數據都保存在關系型數據庫管理系統中(RDBMS關系型數據庫管理系統),客戶端請求時會從RDBMS中讀取數據並在瀏覽器中顯示,這樣當訪問量過大時或集中時,導致RSBMS負擔過重,數據庫響應惡化,瀏覽器中顯示延遲等嚴重問題
  • Memcached 是一套分布式內存對象緩存系統,主要通過緩存數據庫查詢結果,減少數據庫訪問次數,以提高動態 Web 應用的響應速度、提高可擴展性

二、Memcached緩存方式


  • 與APC等本地緩存方式不同,Memcached是分布式的,也就是說它不是本地的;它基於網絡連接(當然它也可以使用localhost)方式完成服務,本身它是一個獨立於應用的程序或守護進程(Daemon方式)
  • Memcached使用libevent庫(程序庫,封裝了linux的epoll、BSD類操作系統的kqueue等事件處理功能)實現網絡連接服務,理論上可以處理無限多的連接,但是它和Apache不同,它更多的時候是面向穩定的持續連接的,所以它實際的並發能力是有限制的;在保守情況下memcached的最大同時連接數為200,這和Linux線程能力有關系,當然這個數值是可以調整的
  • Memcached內存使用方式也和APC不同。APC是基於共享內存和MMAP(將一個文件或者其它對象映射進內存)的,memcachd有自己的內存分配算法和管理方式,它和共享內存沒有關系,也沒有共享內存的限制,通常情況下,每個memcached進程可以管理2GB的內存空間,如果需要更多的空間,可以增加進程數
    技術分享圖片

1.Memcached內存算法

  • Memcached使用[slab allocation][1]機制分配和管理內存,按照預先規定的大小,將分配的內存分割成特定長度的內存塊,再把尺寸相同的內存塊分成組,數據在存放時,根據鍵值大小去匹配slab大小,找就近的slab存放

2.Memcached緩存策略

  • LRU(最近最少使用)加上到期失效策略,當在memcached內存儲數據項時,可指定它在緩存的失效時間,默認為永久;當memcached服務器用完分配的內存時,失效的數據被首先替換,然後是最近未使用的數據
  • LRU中,memcached使用的是一種Lazy Expiration策略(為給定key設置生存時間,當key過期時(生存時間為 0),它會被自動刪除),自己不會監控存入的key/vlue對是否過期,而是在獲取key值時查看記錄的時間戳,檢查key/value對空間是否過期,這樣可減輕服務器的負載

3.Memcached失效策略

Lazy expiration + LRU

  • Lazy expiration作用:假如所存儲的數據項相當多的時候,在這時候進行監控的話,花費的代價是相當大的,所以memcached不會在過期監視上耗費過多的CPU時間,從而在性能方面也起到一定的優化作用
  • LRU:memcached會優先使用已超時的空間,但是還是會有追加信息時空間不足的狀態,這時候會使用Least Recently Used(LRU)機制來分配空間,就從最近未被使用的記錄中搜索,並將其空間分配給新的記錄

4.Memcached分布式算法

當向memcached集群存入/取出key/value時,memcache客戶端會根據一定算法計算存入那臺服務器(第一步:選擇服務器,第二步:存取數據)

  • 余數算法:先求得鍵的整數散列值,再除以服務器數量,根據余數存儲那臺服務器(特點:簡單、高效;但是擴展性差,服務器數量變更時,幾乎所有的緩存都會失效)
  • 散列算法:先計算memcached的散列值,並將其分布在0—2^32的圓上,然後用同樣的方法算出存儲數據鍵的散列值並映射至圓上,最後從數據映射到的位置開始順順時針查找,將數據保存在查找到的第一臺服務器,如果超過2^32還是找不到,則將數據保存在第一臺memcached服務器上;如果添加一臺memcached服務器,則只在圓上添加的逆時針方向的第一臺服務器上的鍵會受到影響
    一次性哈系原理

技術分享圖片

添加一臺服務器後

技術分享圖片

三、Memcached使用場景


  • Memcached應使用在需要"分布式"場合,不需要"共享"的或服務器規模小都不適用;如果將Memcached用於向本地緩存方式使用,速度比PHP的APC慢幾十倍
  • 一般Memcached都用於作為數據庫前端Cache(減少磁盤開銷、SQL解析),並且Memcached是使用內存緩存數據的,比用戶直接訪問數據庫擁有更高的性能,那麽在大型系統中,如訪問數據頻繁的,Memcached可大大降低數據庫壓力、提高效率
  • 並且Memcached不光用於數據庫緩存,除了php中的資源不能存,其它的數據都能存儲(字符串、數值、數組、對象、布爾值、null、二進制(圖片、視頻))
    註:但註意,由於Memcached使用內存緩存,而內存擁有易失性(斷電數據丟失),因此Memcached不能持久保存數據
  • 那麽Memcached瓶頸在哪裏呢?Memcached瓶頸在於網絡,由於Memcached采用"分布式",需要大量數據交換,所以網絡帶寬會經常滿負荷
  1. Memcached不適用於PV不大的網站
  2. Memcached不適用於數據改動頻繁,但數據一改動就需要入庫的情況
  3. Memcached適用於數據改動頻繁、查詢頻繁的情況
  4. Memcached適用於數據庫改動不頻率、查詢頻繁的情況

四、Memcached原理


1.Memcached無緩存

  • 客戶端訪問Web服務器
  • Web服務器調用Memcache客戶端程序庫接口,連接Memcached服務器
  • 如果Memcached沒有緩存客戶端所請求數據,則Memcache客戶端程序將請求轉發到數據庫服務器
  • 數據庫服務器將數據返回給Memcache客戶端程序
  • Memcache客戶端程序收到數據後會通過分布式算法決定將數據緩存到指定Memcached服務器,以供下次使用
  • Memcached緩存完畢後,Memcache客戶端程序將數據返回給Web客戶端,Web客戶端再將數據返回給客戶端

技術分享圖片

2.Memcached有緩存

  • 客戶端訪問Web服務器
  • Web服務器調用Memcache客戶端程序庫接口,連接Memcached服務器
  • 當Memcached中緩存客戶端所需數據,則Memcached將數據庫返回給Memcache客戶端程序
  • Memcache客戶端再將數據交給Web服務器
  • Web服務器將數據返回給客戶端

技術分享圖片

Memcached會在內存裏維護一張巨大的hash表,存儲經常被讀寫的一些數組與文件,在Server端啟動服務進程,在啟動時可以指定監聽的ip,自己的端口號,所使用的內存大小等幾個關鍵參數(采用了單進程,單線程,異步I/O,基於事件 (event_based) 的服務方式)使用libevent作為事件通知實現;每個Server只是對自己的數據進行管理Client端通過指定Server端的ip地址;數據以key -->value形式,key的值通過hash進行轉換,然後通過分布式算法確定對哪臺Sever存儲/獲取數據

五、案例:LAMP+Memcached


主機 系統 IP 網卡 軟件
LAMP+Memcache(Client) Centos 6.7 64Bit 192.168.1.10 vmnet1 LAMP、memcache
Memcached(Server) Centos 6.7 64Bit 192.168.1.100 vmnet1 libevent memcached

Memcached(Server)

1.環境準備(Memcached)

vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0                             //網卡名稱
TYPE=Ethernet                           //網卡類型為以太網
ONBOOT=yes                          //開機自啟該網卡
NM_CONTROLLED=no                        //關閉NetworkManager
BOOTPROTO=static                        //網卡設置為靜態方式
IPADDR=192.168.1.100                    //IP地址配置
NETMASK=255.255.255.0                   //子網掩碼配置
/etc/init.d/network restart     //重啟網絡服務

2.安裝memcached(Memcached)

安裝libevent
libevent是memcached 所依賴的異步時間通知庫,作為Memcached的依賴需要先完成安裝

tar -zxvf libevent-1.4.9-stable.tar.gz -C /usr/src/
cd /usr/src/libevent-1.4.9-stable/
./configure --prefix=/usr/local/libevent
make && make install

安裝Memcached

tar -zxvf memcached-1.2.6.tar.gz -C /usr/src/
cd /usr/src/memcached-1.2.6/
./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent

選項:
--with-libevent:指定libevent事件庫位置

make && make install
echo "PATH=$PATH:/usr/local/memcached/bin">>/etc/profile
source /etc/profile
memcached -d -m 32m -p 11211 -u root                //啟動Memcached服務

參數說明:
-d:啟動為守護進程
-m <num>:分配給Memcached使用的內存數量,單位是MB,默認為64MB
-u <username>:運行Memcached的用戶,僅當作為root運行時
-l <ip_addr>:(小寫L)監聽的服務器IP地址,默認為環境變量INDRR_ANY的值
-p <num>:設置Memcached監聽的端口,最好是1024以上的端口
-c <num>:設置最大並發連接數,默認為1024
-P <file>:設置保存Memcached的pid文件,與-d選擇同時使用

註:啟動過程中會出現"memcached : error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory"錯誤,這是由於Memcached沒有尋找到libevent庫,需在系統中增加libevent庫文件位置
解決方案:
vim /etc/ld.so.conf //打開系統額外加載庫定義文件
/usr/local/libevent/lib //增加libevent事件庫文件夾路徑
ldconfig //重新讀取/etc/ld.so.conf文件內容
memcached -d -m 32m -p 11211 -u root //無報錯
netstat -utpln | grep 11211 //查看Memcahced監聽端口

註:停止Memcached,可使用"pkill memcahced"及"killall memcached"等其它相關方式

LAMP+Memcache(Client)

1.環境準備(LAMP+Memcache)

vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0                             //網卡名稱
TYPE=Ethernet                           //網卡類型為以太網
ONBOOT=yes                          //開機自啟該網卡
NM_CONTROLLED=no                        //關閉NetworkManager
BOOTPROTO=static                        //網卡設置為靜態方式
IPADDR=192.168.1.10                     //IP地址配置
NETMASK=255.255.255.0                   //子網掩碼配置
/etc/init.d/network restart     //重啟網絡服務
yum -y install zlib-devel libxml2-devel libtool-ltdl-devel      //安裝依賴包

2.安裝LAMP(LAMP+Memcache)

安裝httpd

rpm -e httpd httpd-manual webalizer subversion mod_python mod_ssl mod_perl system-config-httpd php php-cli php-ldap php-common mysql dovecot --nodeps
//忽略依賴關系卸載系統已安裝的RPM包軟件(如果有的話,最好輸入確認下)
tar -zxvf httpd-2.2.17.tar.gz -C /usr/src/
cd /usr/src/httpd-2.2.17/
./configure --prefix=/usr/local/httpd --enable-so --enable-rewrite --enable-charset-lite --enable-cgi

選項:
--enable-so:啟動動態加載模塊支持
--enable-rewrite:啟動網頁地址重寫功能
--enable-charset-lite:啟用字符集支持,以支持使用各種字符集編碼的網頁
--enable-cgi:啟用CGI腳本程序支持

make && make install
echo "PATH=$PATH:/usr/local/httpd/bin">>/etc/profile
source /etc/profile
cp /usr/local/httpd/bin/apachectl /etc/init.d/httpd
vim /etc/init.d/httpd
\# chkconfig:35 67 55
\# description: Apache Service
chkconfig --add httpd

安裝MySQL

rpm -e mysql-server mysql           /卸載使用RPM方式安裝MySQL軟件包
yum -y install ncurses-devel cmake  //安裝依賴軟件包
useradd -M -s /sbin/nologin mysql   //新建程序用戶並加入mysql組,不允許登陸系統
tar -zxvf mysql-5.5.22.tar.gz -C /usr/src/
cd /usr/src/mysql-5.5.22/
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DWITH_EXTRA_CHARSETS=all -DSYSCONFDIR=/etc

選項:
-DCMAKE_INSTALL_PREFIX:指定MySQL安裝位置
-DDEFAULT_CHARSET:指定默認字符集編碼
-DDEFAULT_COLLATION:指定默認使用字符集校對規則
-DWITH-EXTRA-CHARSETS:指定額外支持的其他字符集編碼
-DSYSCONFDIR:配置文件存儲位置

make && make install
chown -R mysql:mysql /usr/local/mysql/
cp support-files/my-medium.cnf /etc/my.cnf
/usr/local/mysql/scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data/             //執行初始化腳本

選項:
--user:指定運行用戶
--basedir:指定MySQL數據庫位置
--datadir:指定MySQL數據存儲位置

echo "PATH=$PATH:/usr/local/mysql/bin">>/etc/profile
//添加MySQL到搜索路徑,方便執行命令
source  /etc/profile                    //立即讓profile文件內容生效
cp support-files/mysql.server /etc/init.d/mysqld
//拷貝服務腳本文件到/etc/rc.d/init.d位置
chmod +x /etc/init.d/mysqld
chkconfig --level 35 mysqld on
/etc/init.d/mysqld start 或 service mysqld start
netstat -utpln | grep mysqld

安裝PHP加密工具

rpm -e php php-cli php-ldap php-common php-mysql --nodeps
//忽略依賴關系卸載系統已安裝的RPM包軟件(如果有的話,最好輸入確認下)
tar -zxvf libmcrypt-2.5.8.tar.gz -C /usr/src/
cd /usr/src/libmcrypt-2.5.8/
./configure && make && make install
ln -s /usr/local/lib/libmcrypt.* /usr/lib/
tar -zxvf mhash-0.9.9.9.tar.gz -C /usr/src/
cd /usr/src/mhash-0.9.9.9/
./configure && make && make install
ln -s /usr/local/lib/libmhash.* /usr/lib/
tar -zxvf mcrypt-2.6.8.tar.gz -C /usr/src/
cd /usr/src/mcrypt-2.6.8/
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
./configure && make && make install

安裝PHP

tar -zxvf php-5.3.28.tar.gz -C /usr/src/
cd /usr/src/php-5.3.28/
./configure --prefix=/usr/local/php --with-mcrypt --with-apxs2=/usr/local/httpd/bin/apxs --with-config-file-path=/usr/local/php --enable-mbstring --with-mysql=/usr/local/mysql/

選項:
--with-mcrypt:加載數據加密等擴展工具支持
--with-apxs2:設置Apache HTTP Server提供的apxs模塊支持程序的文件位置
--with-config-file-path:設置PHP的配置文件php.ini將要存放的位置
--enable-mbstring:啟動多字節字符串功能,以便支持中文等代碼
--with-mysql:設置MySQL數據庫服務程序的安裝位置

make && make install

PHP配置(LAMP+Memcache)

cp /usr/src/php-5.3.28/php.ini-development /usr/local/php/php.ini
//拷貝PHP模板文件到PHP工作目錄
vim /usr/local/php/php.ini
        226  short_open_tag = On        //允許識別PHP短語法標記,即<?...?>
        784  default_charset = "utf-8"  //設置默認字符集為utf-8,註意刪除前面";"
tar -zxvf ZendGuardLoader-php-5.3-linux-glibc23-x86_64.tar.gz  -C /usr/src/
cd /usr/src/ZendGuardLoader-php-5.3-linux-glibc23-x86_64/
cp php-5.3.x/ZendGuardLoader.so /usr/local/php/lib/php/
vim /usr/local/php/php.ini
zend_extension=/usr/local/php/lib/php/ZendGuardLoader.so
zend_loader.enable=1
vim /usr/local/httpd/conf/httpd.conf
        310 AddType application/x-httpd-php .php
        167 DirectoryIndex index.php index.html
httpd -t
/etc/init.d/httpd start
vim /usr/local/httpd/htdocs/test1.php               //測試PHP網頁能否正確顯示
<?php
phpinfo();
?>
vim /usr/local/httpd/htdocs/test3.php
<?php
        $link=mysql_connect(‘localhost‘,‘root‘,‘‘);
        if($link) echo "恭喜你,數據庫連接成功啦!";
        mysql_close();
        ?>

3.安裝Memcache(LAMP+Memcache)

tar -zxvf memcache-2.2.7.tgz -C /usr/src/
cd /usr/src/memcache-2.2.7/
/usr/local/php/bin/phpize               //根據系統信息生成對應的configure文件

若出現報錯:
……
Cannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF environment variable. Then, rerun this script.
解決方法:
yum -y install autoconf
註:以上為解決方案,只當執行"/usr/local/php/bin/phpize"報錯時使用

./configure --enable-memcache --with-php-config=/usr/local/php/bin/php-config
make && make install
Build complete.
Don‘t forget to run ‘make test‘.
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/      //復制擴展目錄
vim /usr/local/php/php.ini
        819 extension_dir = "/usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/"      //指定目錄
        820 extension = memcache.so                             //啟動擴展模塊
/etc/init.d/httpd restart
vim /usr/local/httpd/htdocs/test2.php
<?php
$memcache = new Memcache();
        $memcache->connect(‘192.168.1.100‘,11211);
$memcache->set(‘key‘,‘Memcache test successful!‘,0,60);
        $result = $memcache->get(‘key‘);
 unset($memecache);
        echo $result;
?>
//測試調用memcache程序接口來測試memcached服務器與客戶端系統工作是否正常

六、Memcached的使用


Memcached每個被存取的對象都有唯一的標識符key,存取操作均通過key進行,例如可以把後端數據庫中的select操作提取出來,然後對相應的SQL進行hash計算得出key,然後以這個key在memcached中查找數據,如果數據不存在,說明其尚未被寫入緩存中,緩存不存在時將key存儲在緩存中,並設置一個失效時間(比如1小時),在失效時間內的數據都是從緩存中提取,這樣就有效地減少了數據庫的壓力
數據存取命令:

  • set:保存一個數據到服務器上,如已存在則覆蓋
  • add:添加一個數據到服務器,但是服務器必須這個key是不存在的,能夠保證數據不會被覆蓋
  • replace:替換一個已經存在的數據,如果數據不存在,就是類似set功能
  • get:格式是:get <鍵>key;一個不為空的字符串組合,發送這個指令以後,等待服務器的返回;如果服務器端沒有任何數據,則返回"END",證明沒有不存在這個key,沒有任何數據,如果存在數據,則返回指定格式:VALUE <鍵><標記><數據長度>
  • delete:刪除指令;delete <鍵><超時時間><超時時間> - timeout
  • flush_all:這個指令執行後,服務器上所有緩存的數據都被刪除,並且返回
  • stats:顯示當前所有 Memcache 服務器運行的狀態信息

如果只是想獲取部分項目的信息,可以指定參數,格式:stats <參數>:這個指令將只返回指定參數的項目狀態信息
參數:

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:當前線程數   
quit:退出

1.案例(Memcached)

yum -y install telnet
telnet 192.168.1.100 11211          //連接Memcached的11211端口
        Trying 192.168.1.100...
        Connected to 192.168.1.100.
        Escape character is ‘^]‘.
set key 0 60 2
he                      //設置保存key的值
        STORED                  //服務器返回結果,該處代表保存成功
get key                 //獲取key對應的鍵值
        VALUE key 0 2
        he
        END
stats                   //顯示當前所有 Memcache 服務器運行的狀態信息
        STAT pid 12863          //memcached 啟動的進程 ID
        STAT uptime 4008        //到目前為止啟動了多少秒
        STAT time 1464713917    //Unix時間(從1970年1月1日開始統計的秒數)
        STAT version 1.2.6      //memcached 的版本信息
        STAT pointer_size 64        //當前操作系統的指針大小
        STAT rusage_user 0.278957   //進程的累計用戶時間
        STAT rusage_system 0.371943 //進程的累計系統時間
        STAT curr_items 1               //服務器當前存儲的items數量
        STAT total_items 2          //從服務器啟動以後存儲的items總數量
        STAT bytes 79               //當前服務器存儲items占用的字節數
        STAT curr_connections 2     //當前的並發連接數
        STAT total_connections 4        //總的連接數
        STAT connection_structures 3    //服務器分配的連接構造數
        STAT cmd_get 2              //執行 get 命令的次數
        STAT cmd_set 2              //執行 set 命令的次數
        STAT get_hits 2             //get 的命中次數
        STAT get_misses 0           //get 的非命中數
        STAT evictions 0                //為獲取空閑內存而刪除的 items 數
        STAT bytes_read 98          //總讀取字節數(請求字節數)
        STAT bytes_written 97           //總發送字節數(結果字節數)
        STAT limit_maxbytes 33554432 //允許使用的最大內存容量
        STAT threads 1              //當前線程數
        END
quit                            //退出
        Connection closed by foreign host.

2.總結

錯誤
Memcache 的協議的錯誤部分主要是三個錯誤提示之提示指令

  • 普通錯誤信息:ERROR
  • 客戶端錯誤:CLIENT_ERROR <錯誤信息>
  • 服務器端錯誤:SERVER_ERROR <錯誤信息>

數據保存指令

  • 數據保存是基本的功能,就是客戶端通過命令把數據返回過來,服務器端接收後進行處理

指令格式

  &lt;命令&gt;&lt;鍵&gt;&lt;標記&gt;&lt;有效期&gt;&lt;數據長度&gt;

set key 0 60 10

服務器端的返回

  • 數據保存成功(STORED)
  • 數據保存失敗(NOT_STORED),一般是因為服務器端這個數據key已經存在了
  • set後如無任何返回,一般為設置的數據長度未使用完,服務器等待使用完畢

Memcached高性能內存對象緩存系統