這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
最近開源了 Codis,在 Github 上的反響挺不錯的,3天已經收集到了 1000 多 stars, 讓我比較吃驚。也從側面說明了確實分布式緩衝是大家都會遇到的問題。於是我打算在本篇和接下來的幾篇 Blog 詳細說明一下 Codis 的設計和一些背後的考慮,以及對於分布式儲存(尤其是緩衝)系統的一些思考。
Why proxy?
Codis 的架構採用了 Proxy-based 的設計,沒有走官方 Cluster 的路,官方的 Cluster 實現是 P2P 的模型,依靠 Gossip 協議進行訊息同步和將資料分若干個 Slot 作為管理的單位,用戶端需要更改。這個模型的好處是:
- 真正的無中心節點
- 對於用戶端來說請求的效能不會損失太多
但是缺點同樣明顯:
- 狀態很難明確,你很難清楚的知道叢集現在處於什麼狀態
- 對與redis來說,叢集的升級困難,營運困難,因為它將分布式的邏輯和儲存引擎綁定在了一起。
- 需要依賴 smart client
這兩個缺點幾乎在任何 p2p 模型的分布式系統中都存在,由於第一個問題,導致開發和調試的過程也異常艱辛(官方的 cluster 幾乎寫了 3 年才比較穩定)
而 Proxy-based 的方式的好處就比較明顯了:
- 開發成本低
- 業務的切換成本低
- Proxy 的邏輯和儲存的邏輯是隔離的
所以,在 Codis 之前,Twemproxy 是這個方案的最優的選擇,應用也非常廣泛,許多大型的互連網公司都在使用它,但是 Twemproxy 也有它的問題, 最大的問題是:Twemproxy 真的就只是一個 Proxy 而已, 叢集的功能完全沒有。而且看上去 Twitter 也不打算繼續維護它了。
Twitter 最近的一個 Talk,提到了Twitter 內部對於 Scaling Redis 的一些做法和想法,其中對於 Proxy 的方案是比較推崇的(同時也提到了他們內部也不再使用 Twemproxy 了….),裡面理由寫得比較清楚了,有興趣的可以去看看。同樣的, Facebook 之前那篇關於擴充 memcached 的論文也提到了類似的方案 (mcrouter)。其中我覺得這個方案背後最重要的思想就是:儲存和分布式邏輯分離。至於因為轉寄請求而損失的效能,可以通過其他的方式補回來, 比如水平擴充 Proxy。帶來的好處是整個系統的狀態非常清晰,幾乎所有組件都可以獨立的部署和升級,程式還比較好寫,所以 Codis 從一開始就堅定的走 Proxy 這條路。
但是相對於 Twemproxy, Codis 又有一些改進,首先整合了叢集的功能,使用 Presharding 對分散資料的儲存。所有的叢集狀態資訊依賴 ZooKeeper 進行同步, 所有的 Proxy 是無狀態的。這樣就可以實現多 Proxy 的水平擴充。
另外一個比較重要的決定是使用 Go 作為主要開發語言,拋掉信仰問題不談 (我和 @goroutine 都是 go 的腦殘粉), go 幾乎就是針對這種後端的網路程式而發明出來的語言,這給開發工作帶來了極大的效率提升,從寫下第一行代碼,到第一個可用版本,幾乎才用了不到一個月的時間。
當然,使用多 Proxy 對於遷移過程中資料一致性帶來一些問題,會在下一篇 blog 介紹一下 Codis 是怎麼解決的。