memcache詳解

一、緩存服務器相關概念
二、memcache簡介
三、memcache配置實現
四、memcache整合

一、緩存服務器相關概念

專用緩存服務器:squid,varnish,memcached,redis
第三方模塊的緩存:nginx,http

squid:太古老,不推薦
varnish用來做網站和小文件的緩存,相當給力的,做圖片cache之類的合適,varnish沒有專門的存儲引擎,但是不能cache到本地硬盤上的。
Varnish可以使用正則表達式快速、批量地清除部分緩存,varnish的內存管理完全交給內核,當緩存內容超過內存閾值時,內核會自動將一部分緩存存入swap中讓出內存。以挪威一家報社的經驗,1臺varnish可以抵6臺squid的性能。
nginx:nginx本來是反向代理/web服務器,用了插件可以做做這個副業,但是本身不支持的性能比較多。

CDN選型:

1)單點問題

防止單點問題,但是如果只是簡單做負載均衡,單臺CDN server上需要存儲全部數據,存儲利用率太低了。
squid支持幾個實例並聯,實際使用的人不多;
varnish 只能用單實例;
nginx+memcache 天然的分佈式存儲;
採用squid/varnish 也有解決辦法: 需要在它們前面部署一個支持url hash的負載均衡設備(硬件,軟件均可,比如說haproxy)

2)內存存儲的代價

CDN把緩存放在內存當中,提升性能。但是當服務遭遇故障重啓之後,全部數據都會丟失需要重建,這個時候會給後端應用服務器帶來很大的短時壓力服務需要較長的時間才能完全恢復.
而實際運行當中,由於各種原因,CDN服務重啓的概率相當高.

3)動態請求

動態網頁使用CDN,無論squid還是varnish都不能直接用,都需定製代碼。這樣面臨的問題是命中率高低和維護成本的問題

4)purge效率

purge就是CDN刪除緩存項的接口,國內的UGC網站,因爲嚴厲的內容檢查制度和氾濫的垃圾廣告,刪帖子刪圖片特別頻繁,某些網站可能高達40%(發100個貼,有40個帖子可能被刪除或者修改),所以對purge的效率有要求。
squid和varnish的purge效率都達不到國內這種強度要求,nginx+memcache purge性能要好很多。
在國內,遇到突發事件後,要是不及時刪除指定的鏈接或內容,後果可能會很嚴重(小到個人被炒,大到公司被關都有可能)

5)推薦

中小型網站直接買CDN服務就好,現在CDN已經進行按需付費的雲計算模式了,性價比是可以準確計算的;
外地部署單點,推薦用squid;
準備在公司內部實施私有云戰略,推薦nginx+memcache;
不太建議使用varnish。

二、memcache簡介

1、數據結構模型:

結構化數據:關係型數據庫;//多表查詢是一個非常慢的過程,佔用大量的內存,甚至磁盤空間 //關係型數據庫在個應用場景中都成爲了瓶頸
半結構化數據:xml,json,...(NoSQL)
非結構化數據:文件系統,
所有的緩存都是kv數據:
k:查詢語句或者訪問的資源的 url
v:所對應的文件對應的md5碼,可以分級存儲
//查詢時間是恆定的,O(1),速度很快
k/V存儲:
memcached:存儲於內存中,部署相對簡單
redis: 存儲於內存中,週期性將數據同步於disk上

2、memcached:

Livejournal旗下的Danga Interactive
c++裏分配內存有兩種方式,預先分配和動態分配,顯然,預先分配內存會使程序比較快,但是它的缺點是不能有效利用內存,而動態分配可以有效利用內存,但是會使程序運行效率下降,memcached的內存分配就是基於以上原理,顯然爲了獲得更快的速度,有時候我們不得不以空間換時間。
memcache的內存存儲:
Memcache使用了Slab Allocator的內存分配機制:按照預先規定的大小,將分配的內存分割成特定長度的塊,以完全解決內存碎片問題。
Memcache的存儲涉及到slab,page,chunk三個概念
1.Chunk爲固定大小的內存空間,默認爲48Byte。
2.page對應實際的物理空間,1個page爲1M。
3.同樣大小的chunk又稱爲slab。
Slab Allocator的缺點:特定長度的內存,因此無法有效利用分配的內存。例如,將100 字節的數據緩存到128 字節的chunk 中,剩餘的就浪費了
Grow Factor:增長因子 //控制slab之間的差異
memcached 在啓動時指定Growth Factor 因子(通過f 選項),就可以在某種程度上控制slab 之間的差異。默認值爲1.25。但是,在該選項出現之前,這個因子曾經固定爲2,稱爲“powers of 2”策略。
memcache啓動verbose查看:

    slab class 1: chunk size 128 perslab 8192
    slab class 2: chunk size 256 perslab 4096
    slab class 3: chunk size 512 perslab 2048
    ... n爲(n-1)*2

特性:
1.k/V緩存:可以緩存所有的可序列化數據
//數據能夠打散存儲,還能夠還原的數據
存儲項:key,value,flag,expire time;
2.功能的實現一半依賴於服務端,一半依賴於客戶端
3.分佈式緩存:可能一個數據分段後分別存儲在多個s上
//各緩存s互不通信
4.O(1)的執行效率,
5.清理過期數據,LRU(內存不足時開啓):最近最少使用 //Memcached 不會釋放已經分配的內存,記錄過期之後,客戶端無法再看到這一條記錄,其存儲空間就可以利用。
緩存項過期 //memcahe自身不會檢測是否過期,而是在get 時查看記錄的時間戳,檢查記錄是否過期。這種技術被稱爲lazy(惰性)expiration。因此,memcached不會在過期監視上耗費CPU 時間
緩存空間用盡
memcached -M //禁用LRU

3、序列化數據:

含義:將一個對象的狀態(各個屬性量)保存起來,然後在適當的時候再獲得。
序列化分爲兩大部分:序列化和反序列化。序列化是這個過程的第一部分,將數據分解成字節流,以便存儲在文件中或在網絡上傳輸。
反序列化就是打開字節流並重構對象。對象序列化不僅要將基本數據類型轉換成字節表示,有時還要恢復數據。恢復數據要求有恢復數據的對象實例。
特點:如果某個類能夠被序列化,其子類也可以被序列化。
用途:
一:對象序列化可以實現分佈式對象。
二:對象序列化不僅保留一個對象的數據,而且遞歸保存對象引用的每個對象的數據。
可以將整個對象層次寫入字節流中,可以保存在文件中或在網絡連接上傳遞。
利用對象序列化可以進行對象的"深複製",即複製對象本身及引用的對象本身。序列化一個對象可能得到整個對象序列。
目的:序列化的目的是爲了便於傳輸,要點在於能夠保存對象的狀態信息,進行傳輸

4、緩存系統的種類

代理式緩存:例如nginx做proxy,假如本地緩存沒有,nginx會代client去向RS請求
旁路式緩存:假如本地緩存沒有命中,client需要自己去找存儲端取,
//一半在memecache中一半在client端
//client決定是否查找緩存,以及查找哪個緩存,查找完後,是否緩存下來
如何保證在緩存系統中,(確定是否有緩存)一次命中//有就返回,沒有就直接說沒有

5、memcache的分佈式

memcached 不互相通信的分佈式
memcached 儘管是“分佈式”緩存服務器,但服務器端並沒有分佈式功能。各個memcached 不會互相通信以共享信息。那麼,怎樣進行分佈式呢?這完全取決於客戶端的實現。

6、基於緩存查詢算法實現:

1)取模法,(餘數)
把key進行hash,對s的數量取模,(只要key沒有變,他的hash碼就沒有變)
緩存數據的時候,取模後,存儲在對應的s上[例如S3],查詢的時候,同樣對key取模,到對應s上去查看
缺陷:主機故障,少了一臺,所有原有key都失效了,因爲s數量已經發生改變,緩存對應數據取模也發生了改變 //現在的大站點,高度依賴於緩存系統,一個故障,全部玩完

2)一致性hash算法
對s的ip進行hash,然後對2^32取模,數值範圍{0-[2^32-1]}
對key做hash然後2^32取模, //順時針距離他最近的節點做緩存節點
0——[2^32-1] //組成一個環,
查找:對key做hash,取模,然後順時針找距離他最近的
//即使有一臺緩存s掛了,不影響其他s的緩存
極端情況:hash碼偏斜
對A,B,C做hash的結果如下,A會承載了多半的負擔
圖1:
memcache詳解

三、memcache配置實現

[root@localhost ~]# rpm -ql memcached

/etc/sysconfig/memcached  //修改該配置文件,定義
/usr/bin/memcached
/usr/bin/memcached-tool
/usr/lib/systemd/system/memcached.service

連配置文件都沒有,啓動的時候直接定義選項即可
systemctl start memcached //tcp,dup 11211

1、memcache常見命令

telnet 127.0.0.1 11211
命令:

    統計類:stats 
        stats items
        stats slabs
        stats sizes
STAT limit_maxbytes 134217728      #  分配給memcache的內存大小(字節)
STAT bytes 609350    # 當前服務器存儲items佔用的字節數
STAT curr_items 4668    # 服務器當前存儲的items數量
STAT evictions 0     # 分配給memcache的空間用滿後需要刪除舊的items數,踢出。
STAT reclaimed 27160  #回收再利用,已過期的數據條目來存儲新數據。
    存儲類:set,add,replace,append,prepend
        pepend:前插入
        append:後插入
    獲取數據類:get,delete,incr/decr
    清空:flush_all //清空所有記錄
        //memcached惰性清理,緩存過期了,標識爲0,並不真的清理,只有在滿了的時候清理

set mykey 0 60 11 //標誌 換存時長  字長
hello world
stats items
get mykey

append mykey 0 300 4 //添加4個字符
prepend mykey 0 300 4   

quit //退出
ctrl +u 可以使用

set mykey 0 300 1
0 //存儲數值爲0
get mykey
incr mykey 3 //增加3
get mykey 
decr myeky 3 //減3

2、memcached命令簡介

memcached:

    -l 監聽的地址
    -d 以守護進程模式運行
    -u 運行身份
    -m 內存使用大小,默認64m
    -c max併發連接數,默認1024
    -p 監聽的tcp端口,默認11211
    -U udp,監聽的udp端口,默認11211
    -M 緩存空間耗盡時,向請求者返回錯誤信息,而不是基於LRU算法清理
    -f [factor] growth factor,增長因子
        不斷的增加刪除可能會導致內存碎片
        解決內存碎片的策略:memcached:
            例如對內存進行分片,1k的n個,2k的n個,4k的n個
                根據緩存項的大小進行存放,減少了碎片,但是會造成內存浪費
                一個蘿蔔一個坑,有的蘿蔔大有的蘿蔔小,小蘿蔔佔用大坑,就浪費了
            factor就是增長的因子,  
                每一級比他的上一級大多少,增長倍數
            例如最少:40,下一個就是40*1.25 //默認增長因子是1.25
    -n 最小chunk大小字節  
    -t threads線程數,默認4
[root@localhost ~]# memcached -u memcached -f 2 -vv
slab class   1: chunk size        96 perslab   10922    //大約1M,96*10922/1024=1023KB==1M
slab class   2: chunk size       192 perslab    5461        //每一個slab class上有5461個192Bytes大小的chrunk
slab class   3: chunk size       384 perslab    2730
slab class   4: chunk size       768 perslab    1365
slab class   5: chunk size      1536 perslab     682
slab class   6: chunk size      3072 perslab     341
slab class   7: chunk size      6144 perslab     170
slab class   8: chunk size     12288 perslab      85
slab class   9: chunk size     24576 perslab      42
slab class  10: chunk size     49152 perslab      21
slab class  11: chunk size     98304 perslab      10
slab class  12: chunk size    196608 perslab       5
slab class  13: chunk size    393216 perslab       2
slab class  14: chunk size   1048576 perslab       1  //最大爲1048576,再大不給於緩存,還沒有用完64M,大約使用了14M

每一個大小{96,192...}稱爲一個slab class
例如類別96的緩存項有10922個
類別爲192的緩存項共有5461個

linux內存管理是基於頁面進行管理的
n個4k組成了64M內存空間
每個頁4K大小,每個4k應該屬於一個slab類別,
slab類別中有多個葉匡組成,每個頁框中再次劃分
例如96字節:的共有10922個,等
內存:【slab | slab |slab | .... ... . ... 】
slab: 【slab class 96|slab class 96 | ....】
chunk:塊,
slab:大塊
page:分配給slab的內存空間,默認是1M,分配給slab之後根據slab的大小分成chunk
chunk:用於緩存記錄的內存空間
slab class:特定大小的chunk 組
slab calss和chunk都是抽象的概念,只有page纔是真實的

3、stats輸出

名稱 類型 含義
pid 2604 服務器進程ID
uptime 1061 服務器運行時間,單位秒
time 1543837789 服務器當前的UNIX時間
version 1.4.15 服務器的版本號
rusage_user 0.058755 該進程累計的用戶時間(秒:微妙)
rusage_system 0.110598 該進程累計的系統時間(秒:微妙)
curr_items 0 服務器當前存儲的內容數量
total_items 0 服務器啓動以來存儲過的內容總數
bytes 0 服務器當前存儲內容所佔用的字節數
curr_connections 10 連接數
total_connections 26 服務器運行以來接受的連接總數
connection_structures 11 服務器分配的連接結構的數量
cmd_get 1 取回請求總數
cmd_set 0 存儲請求總數
get_hits 1 請求成功的總次數
get_misses 1 請求失敗的總次數
bytes_read 341 服務器從網絡讀取到的總字節數
bytes_written 7452 服務器向網絡發送的總字節數
limit_maxbytes 67108864 服務器在存儲時被允許使用的字節總數
memcache詳解

4、其他

memcached默認沒有認證機制,但可以藉助於SASL進行認證;
php連接memcached的模塊:
memcache:php-percl-memcache
memcached:php-percl-memcached

yum -y install libmemcached //memcached的c接口
/usr/bin/memaslap
memcapable,memcat,memcp,memdump,memerror,memexist,memflush
memparse,memping,memrm,memslap,memstat,memtouch

提供衆多的memcached工具包
memstat --servers=127.0.0.1 //顯示狀態信息

四、memcache整合

1、安裝PHP的memcache擴展

# tar xf memcache-2.2.5.tgz
# cd memcache-2.2.5
/usr/local/php/bin/phpize
# ./configure --with-php-config=/usr/local/php/bin/php-config --enable-memcache
# make && make install

上述安裝完後會有類似以下的提示:
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/
編輯/usr/local/php/lib/php.ini,在“動態模塊”相關的位置添加如下一行來載入memcache擴展:
extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/memcache.so

而後對memcached功能進行 測試,在網站目錄中建立測試頁面test.php,添加如下內容:

<?php
    $mem = new Memcache;
    $mem->connect("127.0.0.1", 11211)  or die("Could not connect");

    $version = $mem->getVersion();
    echo "Server's version: ".$version."<br/>\n";

    $mem->set('hellokey', 'Hello World', 0, 600) or die("Failed to save data at the memcached server");
    echo "Store data in the cache (data will expire in 600 seconds)<br/>\n";

    $get_result = $mem->get('hellokey');
    echo "$get_result is from memcached server.";         
?>

如果有輸出“Hello World is from memcached.”等信息,則表明memcache已經能夠正常工作。

2、使用libmemcached的客戶端工具:

訪問memcached的傳統方法是使用基於perl語言開發的Cache::memcached模塊,這個模塊在大多數perl代碼中都能良好的工作,但也有着衆所周知的性能方面的問題。libMemcached則是基於C語言開發的開源的C/C++代碼訪問memcached的庫文件,同時,它還提供了數個可以遠程使用的memcached管理工具,如memcat, memping,memstat,memslap等。
1) 編譯安裝libmemcached

# tar xf libmemcached-1.0.2.tar.gz 
# cd libmemcached-1.0.2
# ./configure 
# make && make install
# ldconfig

2) 客戶端工具

# memcat --servers=127.0.0.1:11211 mykey
# memping 
# memslap
# memstat

3、Nginx整合memcached:

server {
    listen       80;
    server_name  www.magedu.com;
    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
            set $memcached_key $uri;
            memcached_pass     127.0.0.1:11211;
            default_type       text/html;
            error_page         404 @fallback;
    }

    location @fallback {
            proxy_pass http://172.16.0.1;
    }
}

參考站點:
http://memcached.org/
https://github.com/memcached/memcached/wiki
https://www.cnblogs.com/kevingrace/p/6188123.html
https://www.cnblogs.com/usa007lhy/p/5503728.html

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