2023年,facebook的memcache節點已經達到了3000個,承載著tb級別的快取資料。但開發和運維人員發現乙個問題,為了滿足業務要求新增了大量新memcache節點,但是發現效能不但沒有好轉反而下降了,當時將這種現象稱為快取的「無底洞」現象。
那麼為什麼會產生這種現象呢,通常來說新增節點使得memcache集群效能應該更強了,但事實並非如此。鍵值資料庫由於通常採用雜湊函式將key對映到各個節點上,造成key的分布與業務無關,但是由於資料量和訪問量的持續增長,造成需要新增大量節點做水平擴容,導致鍵值分布到更多的節點上,所以無論是memcache還是redis的分布式,批量操作通常需要從不同節點上獲取,相對於單機批量操作只涉及一次網路操作,分布式批量操作會涉及多次網路時間。
下圖展示了在分布式條件下,一次mget操作需要訪問多個redis節點,需要多次網路時間。
而下圖由於所有鍵值都集中在乙個節點上,所以一次批量操作只需要一次網路時間。
用一句通俗的話總結就是,更多的節點不代表更高的效能,所謂「無底洞」就是說投入越多不一定產出越多。但是分布式又是不可以避免的,因為訪問量和資料量越來越大,乙個節點根本扛不住,所以如何高效的在分布式快取中批量操作是乙個難點。
下面介紹如何在分布式條件下優化批量操作。在介紹具體的方法之前,我們來看一下常見的io優化思路:
這裡我們假設命令、客戶端連線已經為最優,重點討論減少網路操作次數。
以redis批量獲取n個字串為例,有三種實現方法,如下圖所示。
上面已經給出了io的優化思路以及單個節點的批量操作優化方式,下面我們將結合redis cluster的一些特性對四種分布式的批量操作方式進行說明。
由於n個key是比較均勻的分布在redis cluster的各個節點上,因此無法使用mget命令一次性獲取,所以通常來講要獲取n個key的值,最簡單的方法就是逐次執行n個get命令,這種操作時間複雜度較高,他的操作時間=n次網路時間+n次命令時間,網路次數是n。很顯然這種方案不是最優的,但是實現起來比較簡單,如下圖所示。
jedis客戶端示例**如下:
listserialmget(listkeys)
return values;
}
redis cluster使用crc16演算法計算出雜湊值,再取對16383的餘數就可以算出slot值,同時smart客戶端會儲存slot和節點的對應關係,有了這兩個資料就可以將屬於同乙個節點的key進行歸檔,得到每個節點的key子列表,之後對每個節點執行mget或者pipeline操作,他的操作時間=node次網路時間+n次命令時間,網路次數是node的個數,整個過程如下圖所示,很明顯這種方案比第一種要好很多,但是如果節點數太多,還是有一定的效能問題。
jedis客戶端示例**如下:
mapserialiomget(listkeys) else
}// 從每個節點上批量獲取,這裡使用mget也可以使用pipeline
for(entry> entry : nodekeylistmap.entryset())
return keyvaluemap;
}
redis cluster的hash_tag功能,他可以將多個key強制分配到乙個節點上,他的操作時間=1次網路時間+n次命令時間,如下圖所示。
如下圖所示,所有key屬於node2節點。
jedis客戶端示例**如下:
listhashtagmget(string hashtagkeys)
上面已經對批量操作的四種方案進行了介紹,最後通過下表來對四種方案的優缺點、網路io次數進行乙個總結。
方案優點
缺點網路io
序列命令
程式設計簡單
如果少量keys,效能可以滿足要求
大量keys請求延遲嚴重
o(keys)
序列io
程式設計簡單
少量節點,效能滿足要求
大量node延遲嚴重
o(nodes)
並行io
利用並行特性,延遲取決於最慢的節點
程式設計複雜
由於多執行緒,問題定位可能較難
o(max_slow(nodes))
hash_tag
效能最高
業務維護成本較高
容易出現資料傾斜
o(1)
實際開發中可以根據上表給出的優缺點進行分析,沒有最好的方案只有最適合的方案。
快取無底洞現象
快取無底洞現象 facebook工作人員反應,facebook在2010年左右,memcached節點已經達到3000個,他們發現了乙個問題 memcached連線頻繁,導致效率下降,於是加memcached節點,新增後發現因為連線頻繁導致的效率問題依然存在,這就被稱為 無底洞現象 問題分析 以使用...
三 快取雪崩現象和無底洞現象
一般是有某個節點失效,導致其他節點的快取命中率下降,快取中缺失的資料去資料庫查詢,短時間內,造成資料庫伺服器崩潰 重啟db,短時間又被壓垮,但快取資料也多了一些,db反覆多次啟動,快取重建完畢,db才穩定執行 案例 乙個上千萬pv的門戶 快取生命週期設定了6小時,當等到6小時快取失效後,之前放到快取...
php快取優化
2,eaccelerator。通過將php指令碼快取在其編譯狀態來提高指令碼的效能,從而消除編譯的開銷,它還優化指令碼以加速其執行,eaccelerator通常可以減少伺服器開銷,並將php 的速度提公升1 10倍。eaccelerator將編譯的php儲存在共享記憶體中,並直接從中執行 他只是在短...