消息傳輸的設計方式:不單是消息或存儲

編譯 | 麥克周

編輯 | Vincent

AI前線出品| ID:ai-front

AI 前線導語:「原作者郭斯傑的文章主要是圍繞 Pulsar、DistriutedLog 兩者如何與 BookKeeper 協作完成實時處理的經驗分享。本文作者將會解讀他的這篇文章,並且加入作者自己的實際理解和使用經驗」。

寫在前面

這幾天拜讀了郭斯傑的《Messaging,Storage,or both?》一文,原文地址在這裡:

streaml.io/blog/messagi

大有感觸,作者分享了自己過去幾年時間裡在工作中使用 Apache Pulsar、DistributedLog,以及 BookKeeper 的實際經驗。

郭斯傑 7 年前作為雅虎北京的推送消息團隊成員開始使用 BookKeeper,大約 5 年前,也就是 2012 年,郭斯傑轉戰到了位於舊金山的 Twitter 公司,開始致力於利用 BookKeeper 解決分散式資料庫的一致性問題,根據他的描述,這一工作內容最終促成了 Apache DistriutedLog 的誕生。

郭斯傑的這篇文章主要是圍繞 Pulsar、DistriutedLog 兩者如何與 BookKeeper 協作完成實時處理的經驗分享。本文我將會解讀他的這篇文章,並且加入我自己的實際理解和使用經驗。

預備知識

郭斯傑最早開始接觸的是 BookKeeper,從後面的文章介紹中我們可以知道,BookKeeper 是很多組件的基礎,可以幫助進行分散式環境的信息協同管理,正是由於擁有 BookKeeper 的實際工作經驗,郭斯傑也有了接觸 Pulsar 和 DistributedLog 的機會。我先談談自己整理的一些相關知識,介紹這三個東西究竟是什麼?

Apache Pulsar

Pulsar 是分散式訂閱發布消息傳輸系統,最早有由 Yahoo 公司開發的,並在 2016 年正式開源。

Pulsar 提供了靈活消息傳輸、多租戶、跨地理位置數據複製等特性。Pulsar 的創始人 Joe 和 Matteo 等人認為需求是 Pulsar 項目啟動的原因,如果應用程序提供實時服務,需要保證平均 5ms 以內的發布延遲,99% 的請求不會超過 15ms 的延遲,同時滿足分類、強持久性以及傳輸保證等特徵的消息傳輸系統,這個系統必須滿足提交到各個磁碟或者節點達到 99.99% 的準確性。

Pulsar 對於消息的相關概念和角色定義與 Kafka 很相近,它們都把數據的接入方叫做生產者,都把數據的接收方叫做消費者(訂閱者),如下圖所示。

Pulsar 是如何實現對於多租戶用例的支持的?通過屬性(Property)和命名空間 (NameSpace)。屬性表示系統中的租戶,在 Pulsar 集群內部,一個屬性可以包含多個命名空間,如下圖所示。

命名空間是 Pulsar 集群的最基本管理單元,在命名空間級別,你可以設置許可權、調優複製策略、管理跨集群的消息數據複製、控制消息過期,以及其他關鍵操作。同一個命名空間里的主題共享相同的配置。

在 Pulsar 內部存在幾個一對多的關係。一個命名空間對應多個主題(Topic),一個主題對應多個訂閱者(Subsribes),一個訂閱者可以接收主題上的所有消息。為了提供更加靈活的訂閱方式,Pulsar 提供了三種不同的訂閱類型:

  • 獨佔式訂閱:每個主題有且僅有一個消費者;
  • 共享式訂閱:多個消費者可以共享一個訂閱 / 主題,每個消費者可以收到訂閱的某一部分內容;
  • 失敗切換模式:多個消費者可以連接到一個主題,但是同時有且僅有一個消費者可以收到消息,其他的消費者只有在當前在線的那個消費者離線時才能競爭上崗(同樣只會有一個競爭獲勝者,其它競爭失敗者還是需要繼續守候下一次競爭)。

除此之外,Pulsar 支持將主題進行分區,一旦分區,數據也會被自動分區,如下圖所示,和 Kafka 類似,Pulsar 也引入了「Broker」概念,每個 Broker 管理多個主題。

Apache DistributedLog

DistributedLog 的出現是數據層面抽象的必然結果。2012 年底這個時間段正好是 Twitter 公司內部的實時消息基礎設施的雜亂無章階段。Kestrel 是一款隊列系統,被設計用來處理在線服務的關鍵消息,Kafka 則被用於進行離線服務的日誌收集和分析,郭斯傑的團隊則使用 BookKeeper 進行資料庫備份。

DistributedLog 也被稱為「共享日誌基礎設施」。日誌存儲是幾乎所有分散式系統都需要解決的問題,而 DistributedLog 被設計來解決這一共有需求,也可以統一分歧,逐漸變成其他服務的基礎組件,包括鍵值對資料庫、訂閱發布消息,以及跨數據中心的複製機制等等。

下面這張圖詮釋了 DistributedLog 和 BookKeeper 的使用案例。

DistributedLog 最初的定義就是共享的日誌組件,它會跟蹤分散式交易日誌的改變。DistributedLog 是基於 BookKeeper 的,它利用了 BookKeeper 的低延時存儲、並行複製、簡單重複讀一致性、快速多對多複製修復、I/O 隔離,以及簡單操作性,實現了無縫連接歷史和未來數據的設計目標。

Kafka 與 DistributedLog 有一些不同,Kafka 最初就是作為一個日誌收集系統,進而形成了一個消息系統,但是 DistributedLog 開始是為了解決資料庫一致性問題,逐漸形成了流式的存儲系統。這就意味著兩者有較大的設計和技術實現差異,因為 Kafka 的設計初衷就是為了實現數據的交換,它是作為消息中間件設計的,不會僅僅考慮數據一致性問題,兩者看待問題的格局不一樣。現在 DistributedLog 已經被作為 BookKeeper 的一個子項目在運行了。

Apache BookKeeper

BookKeeper 是一款可擴展、容錯、低延時的日誌存儲服務,尤其針對實時任務流設計。

BookKeeper 最初是由 Yahoo 公司開發的,2011 年被合併到了 Apache ZooKeeper,作為它的子項目。2015 年單獨成為 Apache 頂級項目。

BookKeeper 集群由以下兩個組件組成:

  • bookies:代表一系列獨立的存儲服務;
  • metadata 存儲:服務發現和元數據管理。

BookKeeper 客戶端使用 DistributedLog 的 API 或者原生 API 提供對於 bookies 的訪問方式,架構圖如下所示。

BookKeeper 支持以下需求:

  • 客戶端寫入和讀取數據需要低於 5ms 的延時,同時確保數據不丟失(強持久性);
  • 數據存儲應該是持久化的、一致性的、容錯的;
  • 客戶端寫入時可以在數據的尾部寫入,並支持快速存取數據;
  • 支持存儲、訪問歷史和實時數據。

BookKeeper 針對每一份數據需要複製和存儲多份副本,對於複製演算法,這一點和其他的分散式系統有所不同,BookKeeper 使用的是一種被稱為「仲裁併行複製演算法(quorum-vote parallel replication algorithm)」的演算法,該演算法確保了低延時複製數據,這一點有別於 HDFS、Ceph、Kafka 的 Master/Slave 模式,BookKeeper 更加偏向於無中心化。

如上圖所示,可以理解到以下觀點:

  1. bookies 是自動從 BookKeeper 集群里選擇的,ledger 作為一組順序記錄的抽象,類似一個文件名;
  2. 被存儲在 ledger 上的數據記錄會被同時寫入到集群上的其他 bookies 節點;
  3. 當客戶端寫入數據時,客戶端需要等待一定數量的副本確認寫入後才能收到成功消息。這一點和 Cassandra 類似,都是需要遵從 R+W>N 的公式約束,以確保返回的數據是最新的且數據不丟失;
  4. 集群內部支持 bookie 的容錯處理。

深入理解三者關係

Pulsar 的出現是為了解決當前開源的消息系統存在的一些弱點。據郭斯傑介紹,最開始的時候使用 BookKeeper 作為針對 ActiveMQ 的持久化消息存儲,隨後引入了統一靈活消息傳輸模型(Unified Flexible Messaging Model)概念,為什麼這裡稱之為統一呢?我們需要先來了解一下傳統的消息模式。郭斯傑介紹,一般來說,我們有兩種傳統的消息模型:隊列和發布訂閱。隊列是點對點的通信模式,通常是無序消息傳輸,用於無狀態應用比較多一些。對於隊列的消費設計,通常存在一個消費池概念,消費者可以從服務端讀取消息,每條消息僅僅能被傳遞給一個消費者。這種方式允許你對跨越多個消費者實例的處理數據進行分段處理,並且也容易對處理過程通過橫向擴展方式提升性能。訂閱發布模式則是一種廣播通信模式,消息可以被廣播給所有的消費者。當前幾乎所有的消息組件都會分割對於這兩種消息傳輸模式的支持方案,即形成兩套方案,分別對應隊列和主題(Topic)。郭斯傑也舉例了確實存在一些消息組件嘗試去合併這兩種不同的通信模型,例如 Twitter 的 Kestrel,但是最終這樣做的性價比不高。就我個人的使用經驗來看,當前比較主流的 Kafka 採用的是發布訂閱模式,當然,採用哪種方式本質上沒有對錯之分,重要的是和你的業務需求契合。

郭斯傑將 Pulsar 的消息模型方式概括為「生產者 - 主題 - 訂閱 - 消費者」,或者簡稱 PTSC。通過 PTSC 模式,每一條消息都可以與主題相綁定,然後通過 BookKeeper 複製到不同的機器上,接著可以被消費者任意消費。消費者存在組的概念,每一組內的消費者可以決定自己的消費方式(獨佔式、共享式,或故障轉移方式)。下面這張圖解釋了 Pulsar 支持的訂閱模式。

郭斯傑提出了一種觀點,他認為一些基於分區的訂閱發布消息組件誤導了人們對於隊列和流的概念,這些組件強迫消費者按照同一種模式進行消息處理。舉個例子,對於隊列用例,用戶不得不增加分區以用於匹配消費者並行需求,這種方式降低處理的效率,特別是對於任務派發這樣的功能。我主持研發的系統的一個功能就包含任務派發,對於任務派發功能,我們可以有很多種不同的實現方式,多數情況是有多個接收端,這個時候如果需要通過增加隊列方式,確實很不方便,所以郭斯傑提出的用例問題確實存在。

Pulsar 是怎麼滿足隊列需求的?郭斯傑解釋它是通過基於輪詢演算法的共享訂閱模式,允許應用程序在一個訂閱過程中進行分割處理,這樣我們就可以實現在一個主題內部通過增加消費者數量的方式擴展並行處理能力。Pulsar 通過將發布並行性和消費並行性擴展分離方式,允許活動的發布和消費兩者獨立擴展,互不約束對方。

正是由於 Pulsar 是構建於 BookKeeper 之上的,所以可以提供高性能的隊列和流式處理。BookKeeper 不僅僅有助於隊列、流式處理的高性能,也幫助 Pulsar 有效地實現消息刪除功能,而這一項恰恰是其他主流消息組件的弱項。

Pulsar 利用游標系統實現高效的消息移除。我插一句話,對於游標,熟悉 C 語言的同學應該有點映像,它對於數據的移動非常高效。據郭斯傑介紹游標是 Pulsar 用來為每個訂閱者記錄消息消費的重要狀態信息。對於一個獨佔式 / 失敗切換訂閱模式,游標是一個偏移量,標記哪一個消費者已經消費了;而對於共享訂閱模式,游標則不僅僅是一個偏移量了,它被用於跟蹤每個消息的消費情況。Pulsar 利用 BookKeeper 特有的 ledgers(ledgers 支持應用程序創建很多獨立的日誌,一個 ledger 是一個遞增的數據結構,通過單一寫入模式保持數據寫入,並且通過複製機制被複制到其他節點上)設計用於記錄游標的更新情況,這樣就相當於通過 BookKeeper 實現了游標信息的高可用性保障,減少了消費者出現異常之後的消息重新傳遞幾率。正因為有了游標,Pulsar 可以針對消息的消費進行跟蹤,也可以進行消息的刪除。據郭斯傑介紹,他們在 Streamlio 使用游標系統解決 Pulsar 發布過程中的性能問題。

總結

從郭斯傑的文章里我們可以知道 Pulsar 是一種支持靈活的消息模式(隊列和訂閱發布)的分散式訂閱系統,背後是通過 BookKeeper 支持高度擴展、持久化流式存儲。Pulsar 聚焦於消息傳輸和消費,允許快速刪除不需要的消息。我認為正是由於背後有可擴展的流式存儲支持,也相應獲得了強一致性保障,並且允許流式計算中的回調數據和重新處理。

BookKeeper 與 DistributedLog 的結合形成了高度可擴展的日誌流存儲系統,對外提供實時的日誌流存儲服務,可以被用來為其他消息組件提供存儲消息服務,例如 Pulsar。但是我們也應該看到 Pulsar 和 DistributedLog 之間確實存在一些技術上的重疊,更多應該從它們所分別對應的應用場景出發進行考慮。如果你正在尋找針對流式數據的實時存儲組件,BookKeeper+DistributedLog 的組合適合你的需求(高吞吐、低延時、持久化複製功能等等)。我認為,如果你需要一個快速、靈活的消息系統,Pulsar 提供了靈活的消息模式,同時支持隊列和發布訂閱兩種模式。

從全文分析來看,我認為 Pulsar 和 DistributedLog/BookKeeper 的組合,即消息 + 存儲的組合可以提供快速、持久、靈活的消息傳輸模式以及高可擴展的流式存儲。

郭斯傑認為現實世界我們不能單純談論消息或者存儲,兩者應該是並存的。對於這個觀點,我也是持支持態度,因為現實的需求往往是需要多種組件協同支持的,即便是實時分析引擎,其實它內部也存在保存任務狀態的持久化組件,只不過看你如何看待保存的數據了。如果沒有持久化、低延時的存儲,消息系統就有可能丟失數據,也就不能滿足計算引擎重複處理數據的要求;如果沒有消息系統,那麼也就無法為實時流、微服務、事件驅動架構等提供靈活的消息傳輸、日誌流存儲等功能,消息和存儲是針對兩個不同技術領域的概念,消息聚焦於傳輸和消費,存儲則聚焦於一致性、持久性和低延時等條件下的存儲和複製數據,同時也支持快速傳播數據的功能。就郭斯傑的這篇文章來看,他告訴了我們 BookKeeper、Pulsar、DistributedLog 三者的關係。我認為,這三個框架的組合已經發展到方案層面上的組合,不再僅僅能夠單獨工作。開源社區應該就三者搭建更好的生態鏈路。相信未來這三者的組合可以為實時消息處理提供更強大的能力支撐。

對本文感興趣的讀者可以訪問以下三個網址了解更多信息:

bookkeeper.apache.org/

bookkeeper.apache.org/d

pulsar.incubator.apache.org

作者介紹

郭斯傑,Twitter Staff Software Engineer,目前就職於 Twitter,任職 Staff Software Engineer,是 Twitter DistributedLog/BookKeeper 的主要負責人。同時也是 Apache BookKeeper 的 PMC Chair。加入 Twitter 之前,就職於 Yahoo。

周明耀,2004 年畢業於浙江大學,工學碩士。13 年軟體研發經驗,近 10 年技術團隊管理經驗,4 年分散式計算、大數據技術經驗。出版書籍包括《大話 Java 性能優化》、《深入理解 JVM&G1 GC》、《技術領導力 - 碼農如何才能帶團隊》,個人公眾號「麥克叔叔每晚 10 點說」出品人。個人微信號 michael_tec。


-全文完-

關注人工智慧的落地實踐,與企業一起探尋 AI 的邊界,AICon 全球人工智慧技術大會火熱售票中,8 折倒計時一周搶票,詳情點擊:

t.cn/Rl2MftP

《深入淺出TensorFlow》迷你書現已發布,關注公眾號「AI前線」,ID:ai-front,回復關鍵字:TF,獲取下載鏈接!

推薦閱讀:

TAG:消息 | 数据存储技术 |