[譯] 讓 Apache Cassandra 尾部延遲減少 10 倍,已開源

在 Instagram,咱們的數據庫是全球最大的 Apache Cassandra 部署之一。咱們於 2012 年開始用 Cassandra 取代 Redis,來支持欺詐檢測、信息流和 Direct 收件箱等產品需求。最初咱們在 AWS 環境中運行 Cassandra 集羣,但當其餘 Instagram 服務遷移到 Facebook 的基礎設施上時,咱們也遷過去了。對咱們來講 Cassandra 的可靠性和可用性體驗都很不錯,可是在讀取延遲上仍有改進空間。前端

去年,Instagram 的 Cassandra 團隊開始致力於一個項目,目標是顯著減小 Cassandra 的讀取延遲,咱們稱之爲 Rocksandra。在這篇文章中,我將介紹該項目的動機、咱們克服的挑戰以及在內部環境和公共雲環境中的性能指標。android

動機

在 Instagram 咱們大量使用 Apache Cassandra 做爲通用的鍵值存儲服務。大部分 Instagram 的 Cassandra 請求都是實時(Online)的,爲了向巨量的 Instagram 用戶提供可靠和快速的用戶體驗,咱們對這些指標的 SLA(服務等級協議,Service Level Agreement)很是嚴格。ios

Instagram 維護 5-9 秒的可靠性 SLA,這意味着在任什麼時候候,請求失敗率應該小於 0.001%。爲了提升性能,咱們實時監控不一樣 Cassandra 集羣的吞吐量和延遲,尤爲是 P99 讀取延遲。git

下圖展現了生產環境中的一個 Cassandra 集羣的客戶端延遲。藍線是平均讀取延遲(5ms),橙線是 P99 讀取延遲(在 25ms 到 60ms 的範圍內,並隨着客戶端流量變化而變更)。github

通過調查,咱們發現 JVM 垃圾收集器(GC)對延遲峯值做出了很大貢獻。咱們定義了一個叫作 GC 暫停(GC stall)百分比的度量標準,用於度量 Cassandra 服務器在 stop-the-world GC(新生代 GC)而且沒法響應客戶端請求時所佔時間百分比。這是另外一張圖,顯示了咱們生產環境 Cassandra 服務器的 GC 暫停百分比。在流量最小的時間段內,這一比例爲 1.25%,在高峯時段能夠高達 2.5%。算法

該圖顯示 Cassandra 服務器會把 2.5% 的運行時間用於垃圾收集,而不是響應客戶端請求。GC 開銷顯然對咱們的 P99 延遲有很大影響,因此若是可以下降 GC 暫停百分比,也就可以顯著下降 P99 延遲。sql

解決方案

Apache Cassandra 是一個分佈式數據庫,它使用本身以 Java 編寫的基於 LSM 樹的存儲引擎。咱們發現存儲引擎中的某些組件,例如 memtable、壓縮、讀/寫的代碼路徑等等,在 Java 堆中建立了不少對象,並給 JVM 增長了不少開銷。爲了減小存儲引擎帶來的 GC 問題,咱們考慮了不一樣的方法,最終決定開發一個 C++ 存儲引擎來替代現有的引擎。數據庫

咱們不想從頭開始構建新的存儲引擎,所以決定在 RocksDB 之上構建新的存儲引擎。apache

RocksDB 是一款開源的高性能嵌入式數據庫,用於處理鍵值數據。它用 C++ 編寫,而且提供了 C++、C 和 Java 的官方 API。RocksDB 針對性能進行了優化,尤爲是針對 SSD 這樣的快速存儲設備。它在業界被普遍用做 MySQL、mongoDB 和其餘流行數據庫的存儲引擎。後端

挑戰

在 RocksDB 上構建新的存儲引擎時,咱們克服了三個主要挑戰。

第一個挑戰是 Cassandra 的架構不支持可插拔的存儲引擎,就是說現有的存儲引擎與數據庫中的其餘組件耦合在一塊兒。爲了在大量重構和快速迭代之間找到平衡,咱們定義了一個新的存儲引擎 API,包括最多見的讀/寫和流接口。經過這種方式,咱們能夠在 API 後面構建新的存儲引擎,並將其插入到 Cassandra 內部的相關代碼路徑中。

其次,Cassandra 支持豐富的數據類型和表模式,而 RocksDB 只提供純粹的鍵值接口。咱們仔細地定義了編碼/解碼算法,以便在 RocksDB 的數據結構之上支持 Cassandra 的數據模型,並支持與原始 Cassandra 相同的查詢語義。

第三個挑戰是流接口。流傳輸是像 Cassandra 這樣的分佈式數據庫的重要組成部分。咱們新增或移除 Cassandra 集羣中的節點時,Cassandra 須要在不一樣節點之間傳輸數據以平衡集羣中的負載。現有的流傳輸實現是基於當前存儲引擎中的內部細節的。所以,咱們必須將它們分離開,創建一個抽象層,並使用 RocksDB API 從新實現流傳輸。爲了提升流吞吐量,目前咱們先將數據寫入到 temp sst 文件,而後使用 RocksDB ingest file API 將它們一次性批量加載到 RocksDB 中。

性能指標

通過大約一年的開發和測試,咱們已經完成了第一個版本的實現,併成功在 Instagram 內部將其推广部署到多個 Cassandra 集羣。在咱們的其中一個生產集羣中,P99 讀取延遲從 60ms 降至 20ms。咱們還觀察到,該羣集上的 GC 暫停從 2.5% 降低到 0.3%,足足減少了 10 倍!

咱們還想驗證 Rocksandra 在公共雲環境中是否會表現良好。咱們使用三個 i3.8 xlarge EC2 實例在 AWS 環境中配置 Cassandra 集羣,每一個實例都有 32 個 CPU 核心,244GB 內存以及 4 個 nvme 閃存磁盤組成的 raid0。

咱們使用 NDBench 做爲基準測試框架,並使用這個框架中默認的表模式:

TABLE emp (
  emp_uname text PRIMARY KEY,
  emp_dept text,
  emp_first text,
  emp_last text`
)
複製代碼

咱們預加載了 2.5 億行每行 6KB 的數據到數據庫中(每一個服務器在磁盤上存儲大約 500GB 數據),並在 NDBench 中配置了 128 個讀取端和 128 個寫入端。

咱們測試了不一樣的負載並測量了平均/P99/P999的讀/寫延遲。如你所見,Rocksandra 提供了更低且更穩定的尾部讀/寫延遲。

咱們還測試了只讀負載,並觀察到在類似的 P99 讀取延遲(2ms)下,Rocksandra 能夠提供 10 倍的讀取吞吐量(Rocksandra 爲 300K/s,C* 3.0 爲 30K/s)。

展望

咱們已經開源了 Rocksandra 代碼庫基準測試框架,你能夠從 Github 上下載並在本身的環境中嘗試!請讓咱們知道它的表現。

做爲下一步,咱們正在積極開發更多的 C* 功能支持,如二級索引,數據修復等等。咱們還在開發一個 C* 可插拔存儲引擎架構,將咱們的工做回饋給 Apache Cassandra 社區。

若是您身處灣區,並有興趣瞭解更多關於 Cassandra 開發的信息,請參加咱們的下一次 聚會活動

Dikang Gu 是 Instagram 的一名基礎架構工程師


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索