原作者:Sijie Guo
翻譯:StreamNative-Sijia
Apache BookKeeper 針對實時工作負載進行了優化,是可擴展、可容錯、低延遲的日志存儲服務。BookKeeper 最初由雅虎研究院(Yahoo! Research)開發,而后于 2011 年作為 Apache ZooKeeper 的子項目孵化,最終在 2015 年 1 月作為 Apache 的頂級項目問世。自最初引入以來,諸如 Twitter、Yahoo!、Salesforce 等公司廣泛使用 BookKeeper 在多種用例中存儲、服務重要數據。在本文中,我將介紹 BookKeeper 如何確保持久性、一致性與低延遲,還會重點介紹 BookKeeper 的保證和關鍵特性,這些內容都是開源的。
在上一篇文章中,我對 Apache BookKeeper 進行了技術層面的概述,并介紹了一些相關的概念和術語。一個 BookKeeper 集群包括:
- Bookies:一組獨立的存儲服務器
- 元數據存儲系統:用于服務發現和元數據管理
BookKeeper 客戶端可以使用較高級別的 DistributedLog API(也稱為日志流 API)或較低級別的 ledger API。Ledger API 允許用戶直接與 bookies 交互。下圖即為 BookKeeper 安裝的典型示例。
流存儲要求
在 Apache BookKeeper 簡介一文中已經提到,實時存儲平臺應該同時滿足以下要求:
- 即使在強持久性條件下,客戶端也能夠以極低的延遲(小于 5 毫秒)讀寫 entry 流
- 能夠持久、一致、容錯地存儲數據
- 在寫入時,客戶端能夠進行流式傳輸或追尾傳輸
- 有效存儲數據,支持訪問歷史數據與實時數據
BookKeeper 通過提供以下保證來同時滿足上述各項要求:
保證 | 說明 |
---|---|
多副本 | 復制數據并將其持久存儲在多臺機器上,或存儲在多個數據中心以保證容錯。 |
持久性 | 復制成功后,可以實現持久存儲數據。在向客戶端發送確認前,強制啟用 fsync。 |
一致性 | 通過簡單、可重復讀取的一致性模型保證不同讀者之間的一致性。 |
可用性 | 通過 ensemble 更改和推測讀取提高讀寫可用性,同時增強一致性和持久性。 |
低延遲 | 通過 I/O 隔離來保護讀寫延遲,同時保持一致性和持久性。 |
多副本
BookKeeper 在一個數據中心內的多個機器上,或是多個數據中心之間,復制每條數據記錄并存儲多個副本(通常是 3 個或 5 個副本)。一些分布式系統使用主/從或管道復制算法在副本之間復制數據(例如,Apache HDFS、Ceph、Kafka 等),BookKeeper 的不同之處在于使用 quorum-vote 并行復制算法來復制數據,以確保可預測的低延遲。圖 2 即為 BookKeeper 集成中的多副本。
在上圖中:
- 從 BookKeeper 集群中(自動)選擇一組 bookies(圖例中為 bookies 1-5)。這一組 bookies 即為給定 ledger 上用于存儲數據記錄的ensemble。
- Ledger 中的數據分布在 bookies 的 ensemble 中。也就是說,每條記錄都存有多個副本。用戶可以在客戶端級別配置副本數,即寫入 quorum 大小。在上圖中,寫入 quorum 大小為 3,即記錄寫入到 bookie 2、bookie 3 與 bookie 4。
- 客戶端向 ensemble 中寫入數據記錄時,需要等待直至有指定數量的副本發送確認(ack)。副本數即為 ack quorum 大小。接收到指定數量的 ack 后,客戶端默認寫入成功。在上圖中,ack quorum 大小為 2,也就是說,比如 bookie 3 和 bookie 4 存儲數據記錄,則向客戶端發送一條確認。
- 當 bookie 發生故障時,ensemble 的組成會發生變化。正常的 bookies 會取代終止的 bookies,這種取代可能只是暫時的。例如:如果 Bookie 5 終止,Bookie x 可能會取代它。
多副本:核心理念
BookKeeper 多副本基于以下核心理念:
- 日志流面向記錄而不是面向字節。這意味著,數據總是存儲為不可分割的記錄(包括元數據),而不是存儲為單個字節數組。
- 日志(流)中記錄的順序與記錄副本的實際存儲順序分離。
這兩個核心理念確保 BookKeeper 多副本能夠實現以下幾項功能:
- 為向 bookies 寫入記錄提供多種選擇,從而確保即使集群中多個 bookies 終止或運行緩慢,寫入操作仍然可以完成(只要有足夠的容量來處理負載)??梢酝ㄟ^改變 ensemble 來實現。
- 通過增加 ensemble 大小來最大化單個日志(流)的帶寬,以使單個日志不受一臺或一小組機器的限制??梢酝ㄟ^將 ensemble 大小配置為大于寫入 quorum 大小來實現。
- 通過調整 ack quorum 大小來改善追加時的延遲。這對于確保 BookKeeper 的低延遲十分重要,同時還可以提供一致性與持久性保證。
- 通過多對多副本恢復提供快速再復制(再復制為復制不足的記錄創建更多副本,例如:副本數小于寫入 quorum 大?。?。所有的 bookies 都可以作為記錄副本的提供者與接受者。
持久性
保證復制每條寫入 BookKeeper 的數據記錄,并持久化到指定數量的 bookies 中。可以通過使用磁盤 fsync 和寫入確認來實現。
- 在單個 bookie 上,將確認發送給客戶端之前,數據記錄已明確寫入(啟用 fsync)磁盤,以便在發生故障時能夠持久保存數據。這樣可以保證數據寫入到持久化存儲中不依賴電源,可以被重新讀取使用。
- 在單個集群內,復制數據記錄到多個 bookies,以實現容錯。
- 僅當客戶端收到指定數量(通過 ack quorum 大小指定)的 bookies 響應時,才 ack 數據記錄。
最新的 NoSQL 類型數據庫、分布式文件系統和消息系統(例如:Apache Kafka)都假定:保證最佳持久化的有效方式是將數據復制到多個節點的內存中。但問題是,這些系統允許潛在的數據丟失。BookKeeper 旨在提供更強的持久性保證,完全防止數據丟失,從而滿足企業的嚴格要求。
一致性
保證一致性是分布式系統中的常見問題,尤其是在引入多副本以確保持久性和高可用時。BookKeeper 為存儲在日志中的數據提供了簡單而強大的一致性保證(可重復讀取的一致性):
- 如果記錄已被引用程序 ack,則必須立即可讀。
- 如果記錄被讀取一次,則必須始終可讀。
- 如果記錄 R 成功寫入,則在 R之前的所有記錄都已成功提交/保存,并且將始終可讀。
- 在不同讀者之間,存儲記錄的順序必須完全相同且可重復。
這種可重復讀取的一致性由 BookKeeper 中的 LastAddConfirmed(LAC)協議實現。
高可用
在 CAP(Consistency:一致性、Availability:高可用、Partition tolerance:分區容錯)條件下,BookKeeper 是一個 CP 系統。但實際上,即使存在硬件、網絡或其他故障,Apache BookKeeper 仍然可以提供高可用性。為保證寫入與讀取的高可用性能,BookKeeper 采用了以下機制:
?????????????????? 高可用類型 ?????????????????? | 機制 | 說明 |
---|---|---|
寫入高可用 | Ensemble 變化 | 當正在寫入數據的 bookie 發生故障時,客戶端會重新選擇數據的放置)。這樣可以確保:在集群中剩余的 bookie 數量充足時,寫入操作總可以實現。 |
讀取高可用 | 隨機讀 | 一些系統僅從一個指定為 leader 的存儲節點讀取數據,例如:Apache Kafka。BookKeeper 的不同之處在于可以使客戶端從ensemble 中的任一 bookie 讀取記錄。這有助于將讀取流量分散到各個 bookie,同時還能減少追尾讀的延遲。 |
低延遲
強持久性和一致性是分布式系統的復雜問題,特別是當分布式系統還需要滿足企業級低延遲時。BookKeeper 通過以下方式滿足這些要求:
- 在單個 bookie 上,bookie 服務器旨在用于不同工作負載(寫入、追尾讀、追趕讀/隨機讀)之間的 I/O 隔離。在 journal 上部署 group-committing 機制以平衡延遲與吞吐量。
- 采用 quorum-vote 并行復制 schema 緩解由于網絡故障、JVM 垃圾回收暫停和磁盤運行緩慢引起的延遲損失。這樣不僅可以改善追尾延遲,還能保證可預測的 p99 低延遲。
- 采用長輪詢機制在 ack 并確認新記錄后,立刻向追尾的寫入者發出通知并發送記錄。
最后,值得一提的是,明確 fsync 和寫入確認的持久性與可重復的讀取一致性對于狀態處理(尤其是流應用程序的 effectively-once 處理)非常重要。
總結
本文解釋了 BookKeeper 如何保證其持久性、一致性、高可用與低延遲。希望本文為你選擇 BookKeeper 作為實時工作負載存儲平臺提供了強有力的支持。在后續文章中,我會深入介紹 BookKeeper 如何復制數據,以及它采用了怎樣的機制能夠在保證低延遲時,同樣保證一致性與持久性。
如果你對 BookKeeper 或 DistributedLog 感興趣,可以通過 BookKeeper email list 或 BookKeeper Slack channel 加入我們的社區。還可以點擊這里下載最新版本(4.5.0 版)的 BookKeeper。