
在互聯(lián)網(wǎng)應(yīng)用場(chǎng)景的網(wǎng)絡(luò)架構(gòu)中基本上用到了memcache,因此memcache作為分布式緩存之一使用是比較廣泛的,本文是阿青多年使用memcache的總結(jié),絕對(duì)價(jià)值不菲,值得一看(以下mc是memcache的簡(jiǎn)稱)。
一.MC適用場(chǎng)景
業(yè)務(wù)上對(duì)數(shù)據(jù)的要求滿足如下方面的場(chǎng)景才適用。
l數(shù)據(jù)變化不頻繁但訪問頻繁
無用戶關(guān)聯(lián)性
有訪問通用性
數(shù)據(jù)安全要求低
數(shù)據(jù)一致性要求低
無持久化要求
例如秒殺、搶購、抽獎(jiǎng)活動(dòng)的商品或禮品庫存計(jì)數(shù)遞減的場(chǎng)景,此場(chǎng)景對(duì)數(shù)據(jù)的可靠一致性要求很高,放在mc不可靠,很有可能被置換出去。
二.緩存key設(shè)置
1.key值最大長度250個(gè)字符,盡可能設(shè)置短些,不能設(shè)置太長,如果太大浪費(fèi)內(nèi)存。
2.key值不能有空格和控制字符等特殊符號(hào),如\n ?\r,最好不要使用中文,如使用了中文要key作MD5。
3.key值需按業(yè)務(wù)邏輯設(shè)置足夠短后再M(fèi)D5,不過key轉(zhuǎn)MD5后需要實(shí)現(xiàn)獲取key的功能,以便于清理mc或排查故障時(shí)需要拿到key。
4.按業(yè)務(wù)邏輯來設(shè)置key,合理設(shè)置緩存key的粒度,以便提高命中率,比如產(chǎn)品終端頁面的某個(gè)豆腐塊是根據(jù)產(chǎn)品小類或品牌等出數(shù)據(jù)的,應(yīng)用小類id或品牌id為基礎(chǔ)設(shè)置key,而不是無腦地使用產(chǎn)品id為基礎(chǔ)設(shè)置key。
三.緩存value值設(shè)置
1. value過期時(shí)間默認(rèn)最大30天,如設(shè)置過期時(shí)間大于30天,值會(huì)設(shè)置不進(jìn)緩存。
2. value最大能存儲(chǔ)1MB,如果數(shù)據(jù)大于1MB可以考慮壓縮或拆分到多個(gè)key中,在應(yīng)用于頁面級(jí)的緩存時(shí)要特別注意。
3.value最好轉(zhuǎn)為string來保存。
4.不要多重嵌套mc緩存。
四.緩存過期時(shí)間設(shè)置
(一)失效時(shí)間設(shè)置的方法
有兩種:
1.相對(duì)時(shí)間:多長時(shí)間,給出過期的時(shí)間長度
如:memcache.set(key,value,new Date(5000))設(shè)置為5秒過期
2.絕對(duì)時(shí)間:到期時(shí)間,給出過期的最后期限
如:memcache.set(key,value,new Date(System.currentTimeMillis()+5000))設(shè)置為5秒過期
當(dāng)部署應(yīng)用的服務(wù)器系統(tǒng)時(shí)間跟mc服務(wù)端的時(shí)間有差距時(shí),使用絕對(duì)時(shí)間就有問題了,所以建議大家設(shè)置mc緩存過期時(shí)間時(shí)都用相對(duì)時(shí)間??聪旅鎚c服務(wù)端源碼就明了。
服務(wù)端的處理
時(shí)間處理源代碼【memcached.c】如下:
#define REALTIME_MAXDELTA 60*60*24*30 ????????????????????//定義30天的秒數(shù)
static rel_time_t realtime(const time_t exptime) {
if (exptime == 0) return 0;
if (exptime > REALTIME_MAXDELTA) { ??????????????????????//超過30天,是絕對(duì)時(shí)間
if (exptime <= process_started) ????????????????????????//小于進(jìn)程啟動(dòng)日期
return (rel_time_t)1; ?????????????????????????????????//
return (rel_time_t)(exptime - process_started); ??//返回進(jìn)程啟動(dòng)之后的時(shí)間差
} else { ??????????????????????????????????????????????????????????????????//不超過30天,是相對(duì)時(shí)間
return (rel_time_t)(exptime + current_time); ??????// exptime + (tvsec - process_started)
}
}
相對(duì)時(shí)間的返回的值是:服務(wù)器當(dāng)前時(shí)間之后的exptime - process_started秒
絕對(duì)時(shí)間的返回的值是:服務(wù)器當(dāng)前時(shí)間之后的(exptime -服務(wù)端當(dāng)前時(shí)間) - process_started秒
可以看到,如果Client和Server時(shí)間不一致,根據(jù)經(jīng)驗(yàn)mc服務(wù)端跑著跑著其服務(wù)端時(shí)間通常會(huì)比系統(tǒng)時(shí)間慢 當(dāng)然偶爾也會(huì)快,如使用絕對(duì)時(shí)間會(huì)有問題,如mc時(shí)間比系統(tǒng)時(shí)間慢時(shí)對(duì)一些過期時(shí)間有嚴(yán)格要求的就不會(huì)按時(shí)過期了,如果快了那緩存幾乎很快都過期,之前攝影部落某臺(tái)mc就是出現(xiàn)這種情況,在訪問量大些時(shí)由于一大部分緩存集體失效導(dǎo)致數(shù)據(jù)庫負(fù)載高。
所以綜上所述使用相對(duì)時(shí)間是比較安全可靠的做法。
(二)緩存時(shí)長的設(shè)置策略
緩存失效時(shí)間設(shè)置加個(gè)隨機(jī)數(shù)來控制,把失效時(shí)間打散,盡可能避免訪問高峰期緩存集體過期而雪崩,比如某個(gè)頁面塊的緩存時(shí)間設(shè)置4小時(shí)*隨機(jī)數(shù),即是這個(gè)頁面塊每份緩存過期時(shí)間不一樣。
獲取隨機(jī)數(shù)的參考代碼:
//隨機(jī)算法把緩存過期時(shí)間打散
privatefloatgetRandomFloat(){
? ? ? ? floatrandomFloat = 0;
? ? ? ? ?while(true){
? ? ? ? ? ? ? ? ? ? randomFloat =newDouble(Math.random()).floatValue();
? ? ? ? ? ? ? ? ? ?if(randomFloat>0){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(randomFloat<0.5){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? randomFloat = randomFloat*2;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?}
? ? ? ? ? ?returnrandomFloat;
}
五.一些重要的參數(shù)設(shè)置
首先保證同一應(yīng)用各臺(tái)服務(wù)器上的mc配置文件一致。
其他一些需要注意注意的參數(shù):
memcached.failover=false
設(shè)置容錯(cuò)開關(guān),設(shè)置為true,當(dāng)前socket不可用時(shí),程序會(huì)自動(dòng)查找可用連接并返回,否則返回NULL。默認(rèn)為true,最好設(shè)置為false,跟failback設(shè)置為true搭配使用,這樣當(dāng)某臺(tái)mc宕機(jī)或其他問題時(shí)讓該臺(tái)的請(qǐng)求直接落到到數(shù)據(jù)庫,當(dāng)恢復(fù)后重新使用,這樣就不影響整個(gè)mc集群的緩存key的重新分配,引發(fā)集群短期的動(dòng)蕩。
memcached.failback=true
設(shè)置連接失敗恢復(fù)開關(guān),設(shè)置為true,當(dāng)宕機(jī)的服務(wù)器啟動(dòng)或中斷的網(wǎng)絡(luò)連接后,這個(gè)socket連接還可繼續(xù)使用,否則將不再使用,默認(rèn)是true,最好設(shè)置為true。
六.一些排查故障的方法
1.用命令查看分析mc的內(nèi)存使用、命中率和mc時(shí)間情況
一般運(yùn)維同事都有安裝部署xmem和xmcstat命令。
如:xmem ?192.168.123.123 11211

分析各臺(tái)mc的Usage和HitRate的值,如果Usage值80%以上時(shí)有效期內(nèi)緩存的置換率會(huì)比較高,所以緩存命中率相對(duì)會(huì)低些,這時(shí)留意加資源。
如發(fā)現(xiàn)某臺(tái)HitRate的值比其他的要低,該臺(tái)mc很有可能有問題。
xmcstat --i="192.168.123.123:11211"

重點(diǎn)留意MC時(shí)間和服務(wù)器系統(tǒng)時(shí)間這兩個(gè)時(shí)間,如果mc時(shí)間比服務(wù)器時(shí)間快很多,如果我們?cè)O(shè)置緩存過期時(shí)間是絕對(duì)時(shí)間的,那肯定會(huì)降低緩存的命中率,所以設(shè)置緩存過期時(shí)間要用相對(duì)時(shí)間。
2.如發(fā)現(xiàn)一些mc值沒過期的情況下靈異消失,一般是某臺(tái)mc有問題或內(nèi)存使用80%以上時(shí)被置換出去了。排查某臺(tái)mc有問題可以telnet上去每臺(tái)mc手動(dòng)get某個(gè)key來看看,當(dāng)然要先要知道該key是hash到那臺(tái)mc。
文/阿青,寫代碼寫詩寫職場(chǎng)的程序猿大叔,傾力原創(chuàng)簡(jiǎn)單實(shí)用的硬干貨,轉(zhuǎn)載此文請(qǐng)聯(lián)系阿青。