一套開源的高性能分佈式內存對象緩存系統
全部的數據都存儲在內存中
支持任意存儲類型的數據
提升網址訪問的速度php
當程序寫入緩存數據請求時,Memcached的API接口將KEY輸入路由算法模塊路由到集羣中的一臺服務,以後由API接口與服務器進行通訊,完成一次分佈式緩存寫入 Key索引創建在API中,值value數據存在後面的memcached中
要依賴於Memcached的客戶端來實現
多個Memcached服務器是獨立的
分佈式數據如何存儲是路由算法所決定前端
求餘數hash算法 先用key作hash運算的到一個整數,再去作hash算法,根據餘數進行路由。不適合在動態變化的環境中 一致性hash算法 按照hash算法把對應key經過必定hash算法處理後映射造成一個首尾接閉合循環,而後經過使用與對象存儲同樣的hash算法將機器也映射到環中,順時針方向計算將全部對象存儲到離本身最近的機器中。適合在動態變化中使用
Memcached是danga.com(運營LiveJournal的技術團隊)開發的一套分佈式內存對象緩存系統,用於在動態系統中減小數據庫負載,提高性能。關於這個東西,相信不少人都用過,本文意在經過對memcached的實現及代碼分析,得到對這個出色的開源軟件更深刻的瞭解,並能夠根據咱們的須要對其進行更進一步的優化。末了將經過對BSM_Memcache擴展的分析,加深對memcached的使用方式理解。c++
在闡述這個問題以前,咱們首先要清楚它「不是什麼」。不少人把它看成和SharedMemory那種形式的存儲載體來使用,雖然memcached使用了一樣的「Key=>Value」方式組織數據,可是它和共享內存、APC等本地緩存有很是大的區別。Memcached是分佈式的,也就是說它不是本地的。它基於網絡鏈接(固然它也可使用localhost)方式完成服務,自己它是一個獨立於應用的程序或守護進程(Daemon方式)。 Memcached使用libevent庫實現網絡鏈接服務,理論上能夠處理無限多的鏈接,可是它和Apache不一樣,它更多的時候是面向穩定的持續鏈接的,因此它實際的併發能力是有限制的。在保守狀況下memcached的最大同時鏈接數爲200,這和Linux線程能力有關係,這個數值是能夠調整的。關於libevent能夠參考相關文檔。 Memcached內存使用方式也和APC不一樣。APC是基於共享內存和MMAP的,memcachd有本身的內存分配算法和管理方式,它和共享內存沒有關係,也沒有共享內存的限制,一般狀況下,每一個memcached進程能夠管理2GB的內存空間,若是須要更多的空間,能夠增長進程數。
在不少時候,memcached都被濫用了,這固然少不了對它的抱怨。我常常在論壇上看見有人發貼,相似於「如何提升效率」,回覆是「用memcached」,至於怎麼用,用在哪裏,用來幹什麼一句沒有。memcached不是萬能的,它也不是適用在全部場合。算法
Memcached是「分佈式」的內存對象緩存系統,那麼就是說,那些不須要「分佈」的,不須要共享的,或者乾脆規模小到只有一臺服務器的應用,memcached不會帶來任何好處,相反還會拖慢系統效率,由於網絡鏈接一樣須要資源,即便是UNIX本地鏈接也同樣。 在我以前的測試數據中顯示,memcached本地讀寫速度要比直接PHP內存數組慢幾十倍,而APC、共享內存方式都和直接數組差很少。可見,若是隻是本地級緩存,使用memcached是很是不划算的。shell
Memcached在不少時候都是做爲數據庫前端cache使用的。由於它比數據庫少了不少SQL解析、磁盤操做等開銷,並且它是使用內存來管理數據的,因此它能夠提供比直接讀取數據庫更好的性能,在大型系統中,訪問一樣的數據是很頻繁的,memcached能夠大大下降數據庫壓力,使系統執行效率提高。另外,memcached也常常做爲服務器之間數據共享的存儲媒介,例如在SSO系統中保存系統單點登錄狀態的數據就能夠保存在memcached中,被多個應用共享。數據庫
須要注意的是,memcached使用內存管理數據,因此它是易失的,當服務器重啓,或者memcached進程停止,數據便會丟失,因此memcached不能用來持久保存數據。不少人的錯誤理解,memcached的性能很是好,好到了內存和硬盤的對比程度,其實memcached使用內存並不會獲得成百上千的讀寫速度提升,它的實際瓶頸在於網絡鏈接,它和使用磁盤的數據庫系統相比,好處在於它自己很是「輕」,由於沒有過多的開銷和直接的讀寫方式,它能夠輕鬆應付很是大的數據交換量,因此常常會出現兩條千兆網絡帶寬都滿負荷了,memcached進程自己並不佔用多少CPU資源的狀況。vim
4 192.168.136.238 主服務器
5 192.168.136.239 從服務器
6 192.168.136.185 客戶端
客戶端訪問的漂移地址 192.168.136.188**數組
[root@localhost ~]# mkdir /abc [root@localhost ~]# mount.cifs //192.168.100.25/memcached /abc #掛載 Password for root@//192.168.100.25/memcached: [root@localhost ~]# cd /abc/ [root@localhost abc]# ls LAMP-php5.6 magent-0.5.tar.gz memcached-1.5.6.tar.gz libevent-2.1.8-stable.tar.gz memcache-2.2.7.tgz [root@localhost abc]# tar zxvf libevent-2.1.8-stable.tar.gz -C /opt #事件庫,memcached依賴於事件庫 [root@localhost abc]# tar zxvf memcached-1.5.6.tar.gz -C /opt/ #服務端memcached [root@localhost abc]# yum install gcc gcc-c++ make -y #安裝環境包 [root@localhost abc]# mkdir /opt/magent [root@localhost abc]# tar zxvf magent-0.5.tar.gz -C /opt/magent/ [root@localhost opt]# cd libevent-2.1.8-stable/ [root@localhost libevent-2.1.8-stable]# ./configure --prefix=/usr [root@localhost libevent-2.1.8-stable]# make && make install #編譯安裝 [root@localhost libevent-2.1.8-stable]# cd ../memcached-1.5.6/ [root@localhost memcached-1.5.6]# ./configure --with-libevent=/usr make make install
[root@localhost ~]# mkdir /abc [root@localhost ~]# mount.cifs //192.168.100.25/memcached /abc Password for root@//192.168.100.25/memcached: [root@localhost ~]# cd /abc/ [root@localhost abc]# ls LAMP-php5.6 magent-0.5.tar.gz memcached-1.5.6.tar.gz libevent-2.1.8-stable.tar.gz memcache-2.2.7.tgz [root@localhost abc]# tar zxvf libevent-2.1.8-stable.tar.gz -C /opt #事件庫,memcached依賴於事件庫 [root@localhost abc]# tar zxvf memcached-1.5.6.tar.gz -C /opt/ #服務端memcached [root@localhost abc]# yum install gcc gcc-c++ make -y [root@localhost opt]# cd libevent-2.1.8-stable/ [root@localhost libevent-2.1.8-stable]# ./configure --prefix=/usr [root@localhost libevent-2.1.8-stable]# make && make install [root@localhost libevent-2.1.8-stable]# cd ../memcached-1.5.6/ [root@localhost memcached-1.5.6]# ./configure --with-libevent=/usr make make install
[root@localhost memcached-1.5.6]# cd /opt/ [root@localhost opt]# ls libevent-2.1.8-stable magent memcached-1.5.6 rh [root@localhost opt]# cd magent/ [root@localhost magent]# vim ketama.h #改兩行 #ifndef SSIZE_MAX #define SSIZE_MAX 32767 [root@localhost magent]# vim Makefile #指定makefile文件,改一行 LIBS = -levent -lm make #編譯 [root@localhost magent]# ls ketama.c ketama.h ketama.o magent magent.c magent.o Makefile [root@localhost magent]# yum install openssh-clients -y #安裝scp遠程同步軟件包 [root@localhost magent]# cp magent /usr/bin/ #把magent腳本放到/usr/local中,讓系統能識別 [root@localhost magent]# scp magent root@192.168.136.239:/usr/bin/ #把mangent文件拷貝到從服務器上
[root@localhost bin]# systemctl stop firewalld.service [root@localhost bin]# setenforce 0
[root@localhost bin]# yum install keepalived -y
[root@localhost magent]# vim /etc/keepalived/keepalived.conf ! Configuration File for keepalived vrrp_script magent { #寫一個函數腳本 script "/opt/shell/magent.sh" ##指定腳本位置 interval 2 ##檢測腳本時間間隔 } global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id MAGENT_HA #主服務器id,兩臺不能同樣 } vrrp_instance VI_1 { state MASTER interface ens33 #主服務器網卡 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 #默認驗證 } track_script { #調函數名magent magent } virtual_ipaddress { 192.168.136.188 #客戶端訪問的漂移地址 } }
[root@localhost bin]# cd /etc/keepalived/ [root@localhost keepalived]# mv keepalived.conf keepalived.conf.bak #更名字 [root@localhost keepalived]# yum install openssh-clients -y
[root@localhost magent]# cd /etc/keepalived/ [root@localhost keepalived]# scp keepalived.conf root@192.168.136.239:/etc/keepalived/
[root@localhost keepalived]# ls keepalived.conf keepalived.conf.bak [root@localhost keepalived]# vim keepalived.conf ! Configuration File for keepalived vrrp_script magent { script "/opt/shell/magent.sh" interval 2 } global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id MAGENT_HB #routed_id不能相同 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 52 #從服務器虛擬id不能和主服務器同樣 priority 90 #優先級比主服務器低 advert_int 1 authentication { auth_type PASS auth_pass 1111 } track_script { magent } virtual_ipaddress { 192.168.136.188 } }
[root@localhost keepalived]# mkdir /opt/shell [root@localhost keepalived]# cd /opt/shell/ [root@localhost shell]# vim magent.sh #!/bin/bash k=`ps -ef | grep keepalived | grep -v grep | wc -l` #檢查keepaliveed進程,若是開啓 if [ $k -gt 0 ]; then # -n鏈接數量 -l指定漂移地址,-p指定端口映射到主從服務器的地址 magent -u root -n 51200 -l 192.168.136.188 -p 12000 -s 192.168.136.238:11211 -b 192.168.136.239:11211 else pkill -9 magent fi [root@localhost shell]# chmod +x magent.sh [root@localhost shell]# systemctl start keepalived.service [root@localhost shell]# netstat -ntap | grep 12000 tcp 0 0 192.168.136.188:12000 0.0.0.0:* LISTEN 124720/magent
[root@localhost keepalived]# mkdir /opt/shell [root@localhost keepalived]# cd /opt/shell/ [root@localhost shell]# vim magent.sh #!/bin/bash k=`ps -ef | grep keepalived | grep -v grep | wc -l` if [ $k -gt 0 ]; then magent -u root -n 51200 -l 192.168.136.188 -p 12000 -s 192.168.136.238:11211 -b 192.168.136.239:11211 else pkill -9 magent fi [root@localhost shell]# chmod +x magent.sh [root@localhost shell]# systemctl start keepalived.service [root@localhost shell]# netstat -ntap | grep 12000 #查看magent端口 tcp 0 0 192.168.136.188:12000 0.0.0.0:* LISTEN 11660/magent
[root@localhost shell]# memcached -m 512k -u root -d -l 192.168.136.238 -p 11211 #啓動主,-m指定空間大小 [root@localhost shell]# netstat -ntap | grep 11211 tcp 0 0 192.168.136.238:11211 0.0.0.0:* LISTEN 44647/memcached
[root@localhost shell]# memcached -m 512k -u root -d -l 192.168.136.239 -p 11211 #啓動從 [root@localhost shell]# netstat -ntap | grep 11211 tcp 0 0 192.168.136.239:11211 0.0.0.0:* LISTEN 42654/memcached
[root@localhost ~]# telnet 192.168.136.188 12000 Trying 192.168.136.188... Connected to 192.168.136.188. Escape character is '^]'. add username 0 0 7 #咱們先寫個鍵值對數據 1234567 STORED
[root@localhost shell]# telnet 192.168.136.238 11211 Trying 192.168.136.238... Connected to 192.168.136.238. Escape character is '^]'. geer^H^H ERROR get username VALUE username 0 7 1234567 END
[root@localhost shell]# telnet 192.168.136.239 11211 Trying 192.168.136.239... Connected to 192.168.136.239. Escape character is '^]'. get username VALUE username 0 7 1234567 END