Scaling Memcache in Facebook 筆記(二)

Scaling Memcache in Facebook 筆記(一)

B. Region Replication

(Region感覺不好翻譯,類似於data center的概念吧)

前面我們談到把一堆Web Server和一堆Memcached作為一個Cluster。但是一個Cluster是不能無限Scale up的,因為每個Cluster裡面都是多對多的Connection,也就是說是N^2的connection上限,這樣N越大,就會:

  1. Hotkey 訪問量越來越大,最終搞得有hotkey的那個server hold不住
  2. 網路堵塞各種丟包
  3. ...

所以,論文提到建立多個Cluster (為了區分,後面把這種每個裡面包含一定數量的Web Server和memcached的cluster稱為Frontend Cluster),把它們和一個Storage Cluster組合起來,組成一個Region。所有Frontend Cluster共享同一個後端服務。

這樣相當於是用空間換時間:同一個key在每一個Frontend Cluster都可能有一個Copy,這樣會帶來consistency的問題(後面會講怎麼解決),但是這樣能夠降低latency和提高availability。

B.1 Regional Invalidation

這裡要解決的問題是:Cluster A的某個Server修改了後端資料庫裡面的值,如何把這個值被修改了的消息傳播到所有的Frontend Cluster,好讓它們把本地memcached對應的舊的數據清掉?

一種簡單的方式是讓那個做出修改的Web Server負責通知同一個Region里所有Cluster的所有memcached,但基於我們上面說到的種種理由,這樣performance會很差,而且還容易由於routing的配置出錯,所以這種操作只能現在在同一個Cluster里。

那麼對於其他Cluster,解決辦法是讓Storage Cluster來負責把消息廣播出去。Storage layer採用的是Mysql,而Mysql對於數據更新是有日誌的。第一步首先在日誌內容里加上對應的memcached key,然後設立一個進程監聽日誌,發現有數據更新,就解析出對應的key,然後把消息廣播給所有的memcached。

這裡有一點要注意的是我們不能讓資料庫直接跟memcached通信,原因包括但不限於:

  1. 這樣通信連接太多
  2. 這樣還得把routing邏輯放到後端邏輯里

所以每個cluster裡面有專門的server,運行mcrouter進程(還記得前面說過routing邏輯可以作為庫函數嵌入,也可以作為單獨的進程運行吧)。廣播消息會發送給這些進程,再由它們負責傳給本cluster的memcached。

B.2 Regional Pool

每個Frontend Cluster都有自己的memcached pools,我們姑且把它們稱作cluster pool吧。與之相對的Regional Pool顧名思義就是被所有cluster共享的memcached pool。為什麼要設立這樣的pool呢?

主要原因是,有一些數據,訪問頻率低,本身占內存還多,這樣的數據放到每個cluster里複製一份,要佔用很多額外的內存。所以把它們放到Regional Pool裡面就可以減少內存佔用。雖然Regional Pool的latency會相對更高(因為要穿越cluster的邊界),但是由於它們訪問頻率不高,所以也就顯得不那麼有所謂了。

論文提到目前是靠人的經驗來覺得什麼東西放Regional Pool的,不知道現在是不是做到自動化了。

B.3 Cold Cluster Warmup

當我們起一個新的cluster,或者把cluster拿去維護,等等等等之類的,這個cluster的cache基本是沒東西的,所以基本很大概率是各種cache miss,然後要等很久才能填得比較滿,而且這樣也會給後端服務帶來很大壓力。

解決辦法嘛,很容易就能想到,允許這個cold cluster在cache miss的時候,把別的「warm cluster」(就是cache有比較多數據的cluster)當作storage cluster去那邊讀數據,這樣原來需要幾天時間才能完成的warm up在幾個小時之內就能完成。

但是這樣又帶來了新的問題。想像下面這個情景:Cluster A某個Server往Storage里更新了一份數據,後端在完成數據更新後會把數據過期的消息發送到其他的Cluster。同時Cluster A里某個Server讀這份數據的時候發現cache miss,然後從Cluster B里讀;如果恰好Cluster B此時還沒有收到數據過期的消息(因為消息傳遞也是要時間的),這個讀會成功返回,然後這個Server拿到事實上已經過期的數據後會往Cluster A的memcached里寫。這樣子就相當於Cluster A的memcached就存放了一份過期的數據,而且這份過期的數據可能被保留很長甚至無限長的時間。

解決辦法是:memcached支持一個功能,在對一個key進行delete操作之後鎖住這個key一段時間不允許進行add操作。通過在cold cluster里設置這段hold-off時間為大於0的值(2秒),在上面的場景中,由於前面那個更新的Server是對本地memcached進行了delete操作的,第二個server拿著過期數據往裡寫的時候就會報錯,然後它就知道這個數據在Storage裡面有新值,就會去讀最新的值再往裡寫。理論上過期數據還是可能出現的,但是可能性大大減低了。

Scaling Memcache in Facebook 筆記(三)

引用:

Scaling Memcache at Facebook (Paper)


推薦閱讀:

分散式系統理論進階 - Raft、Zab
搞分散式,大數據都寫些什麼代碼,是不是寫不了幾行?
bifrost : Rust 下的分散式系統框架
基於分散式環境下限流系統的設計
超級乾貨:Word2Vec課堂筆記(內附教學視頻)

TAG:Facebook | 分布式计算 | 分布式系统 |