1. 程式人生 > >快取系列文章–無底洞問題

快取系列文章–無底洞問題

一、背景 

 1. 什麼是快取無底洞問題:

Facebook的工作人員反應2010年已達到3000個memcached節點,儲存數千G的快取。他們發現一個問題–memcached的連線效率下降了,於是新增memcached節點,新增完之後,並沒有好轉。稱為“無底洞”現象

2. 快取無底洞產生的原因:

鍵值資料庫或者快取系統,由於通常採用hash函式將key對映到對應的例項,造成key的分佈與業務無關,但是由於資料量、訪問量的需求,需要使用分散式後(無論是客戶端一致性哈性、redis-cluster、codis),批量操作比如批量獲取多個key(例如redis的mget操作),通常需要從不同例項獲取key值,相比於單機批量操作只涉及到一次網路操作,分散式批量操作會涉及到多次網路io。

3. 無底洞問題帶來的危害:

(1) 客戶端一次批量操作會涉及多次網路操作,也就意味著批量操作會隨著例項的增多,耗時會不斷增大。

(2) 服務端網路連線次數變多,對例項的效能也有一定影響。
4. 結論:

用一句通俗的話總結:更多的機器不代表更多的效能,所謂“無底洞”就是說投入越多不一定產出越多。

分散式又是不可以避免的,因為我們的網站訪問量和資料量越來越大,一個例項根本坑不住,所以如何高效的在分散式快取和儲存批量獲取資料是一個難點。

二、雜湊儲存與順序儲存

在分散式儲存產品中,雜湊儲存與順序儲存是兩種重要的資料儲存和分佈方式,這兩種方式不同也直接決定了批量獲取資料的不同,所以這裡需要對這兩種資料的分散式方式進行簡要說明:

1. hash分佈:

hash分佈應用於大部分key-value系統中,例如memcache, redis-cluster, twemproxy,即使像mysql在分庫分表時候,也經常會用user%100這樣的方式。

hash分佈的主要作用是將key均勻的分佈到各個機器,所以它的一個特點就是資料分散度較高,實現方式通常是hash(key)得到的整數再和分散式節點的某臺機器做對映,以redis-cluster為例子:

問題:和業務沒什麼關係,不支援範圍查詢。

2. 順序分佈

 3. 兩種分佈方式的比較:

分佈方式 特點 典型產品
雜湊分佈 1. 資料分散度高2.鍵值分佈與業務無關3.無法順序訪問

4.支援批量操作

一致性雜湊memcacheredisCluster其他快取產品
順序分佈 1.資料分散度易傾斜2.鍵值分佈與業務相關3.可以順序訪問

4.支援批量操作

BigTableHbase

三、分散式快取/儲存四種Mget解決方案

1. IO的優化思路:

(1) 命令本身的效率:例如sql優化,命令優化

(2) 網路次數:減少通訊次數

(3) 降低接入成本:長連/連線池,NIO等。

(4) IO訪問合併:O(n)到O(1)過程:批量介面(mget),

2.  如果只考慮減少網路次數的話,mget會有如下模型

3. 四種解決方案:

(1).序列mget

將Mget操作(n個key)拆分為逐次執行N次get操作, 很明顯這種操作時間複雜度較高,它的操作時間=n次網路時間+n次命令時間,網路次數是n,很顯然這種方案不是最優的,但是足夠簡單。

(2). 序列IO

將Mget操作(n個key),利用已知的hash函式算出key對應的節點,這樣就可以得到一個這樣的關係:Map<node, somekeys>,也就是每個節點對應的一些keys

它的操作時間=node次網路時間+n次命令時間,網路次數是node的個數,很明顯這種方案比第一種要好很多,但是如果節點數足夠多,還是有一定的效能問題。

(3). 並行IO

此方案是將方案(2)中的最後一步,改為多執行緒執行,網路次數雖然還是nodes.size(),但網路時間變為o(1),但是這種方案會增加程式設計的複雜度。

它的操作時間=1次網路時間+n次命令時間

(4). hash-tag實現。

第二節提到過,由於hash函式會造成key隨機分配到各個節點,那麼有沒有一種方法能夠強制一些key到指定節點到指定的節點呢?

redis提供了這樣的功能,叫做hash-tag。什麼意思呢?假如我們現在使用的是redis-cluster(10個redis節點組成),我們現在有1000個k-v,那麼按照hash函式(crc16)規則,這1000個key會被打散到10個節點上,那麼時間複雜度還是上述(1)~(3)

那麼我們能不能像使用單機redis一樣,一次IO將所有的key取出來呢?hash-tag提供了這樣的功能,如果將上述的key改為如下,也就是用大括號括起來相同的內容,那麼這些key就會到指定的一個節點上。

例如:

user1,user2,user3......user1000
{user}1,{user}2,{user}3.......{user}1000

例如下圖:它的操作時間=1次網路時間+n次命令時間

3. 四種批量操作解決方案對比:

方案 優點 缺點 網路IO
序列mget 1.程式設計簡單2.少量keys,效能滿足要求 大量keys請求延遲嚴重 o(keys)
序列IO 1.程式設計簡單2.少量節點,效能滿足要求 大量node延遲嚴重 o(nodes)
並行IO 1.利用並行特性2.延遲取決於最慢的節點 1.程式設計複雜2.超時定位較難 o(max_slow(node))
hash tags 效能最高 1.tag-key業務維護成本較高2.tag分佈容易出現數據傾斜 o(1)

四、總結和建議

無底洞問題對資源和效能有一定影響,但是其實大部分系統不需要考慮這個問題,因為

1. 99%公司的資料和流量無法和facebook相比。

2. redis/memcache的分散式叢集通常來講是按照專案組做隔離的,以我們經驗來看一般不會超過50對主從。

所以這裡只是提供了一種優化的思路,開闊一下視野。

五、參考文獻