Pulsar簡介
Apache Pulsar是一個企業級的分布式消息系統,最初由Yahoo開發並在2016年開源,目前正在Apache基金會下孵化。Plusar已經在Yahoo的生產環境使用了三年多,主要服務於Mail、Finance、Sports、 Flickr、 the Gemini Ads platform、 Sherpa以及Yahoo的KV存儲。
Pulsar之所以能夠稱為下一代消息隊列,主要是因為以下特性:
-
線性擴展。能夠絲滑的擴容到成百上千個節點(Kafka擴容需要占用很多系統資源在節點間拷貝數據,而Plusar完全不用)
-
高吞吐。已經在Yahoo的生產環境中經受了考驗,每秒數百萬消息
-
低延遲。在大規模的消息量下依然能夠保持低延遲(< 5ms)
-
持久化機制。Plusar的持久化機制構建在Apache BookKeeper之上,提供了寫與讀之前的IO隔離
-
基於地理位置的復制。Plusar將多地域/可用區的復制作為首要特性支持。用戶只需配置好可用區,消息就會被源源不斷的復制到其他可用區。當某一個可用區掛掉或者發生網絡分區,plusar會在之后不斷的重試。
-
部署方式的多樣化。既可以運行在裸機,也支持目前例如Docker、K8S的一些容器化方案以及不同的雲廠商,同時在本地開發時也只需要一行命令即可啟動整個環境。
-
Topic支持多種消費模式:exclusive 唯一性、shared 共享性、failover(失效備援性(為系統備援能力的一種,當系統中其中一項設備失效而無法運作時,另一項設備即可自動接手原失效系統所執行的工作))
架構概述
從最上層來看,一個Plusar單元由若干個集群組成,單元內的集群可以互相之前復制數據, plusar中通常有以下幾種組件:
-
Broker:負責處理Producer發來的消息並分發給消費者。通過一個全局的ZK集群來處理多種協作式任務,例如說基於地理位置的復制。並將消息存儲到BookKeeper中,同時單個集群內也需要有一套ZK集群,來存儲一些元數據。
-
BookKeeper集群: 內部包含多個bookies,用於持久化消息。
-
ZooKeeper集
Broker
在Kafka和RocketMQ中,Broker負責消息數據的存儲以及consumer消費位移的存儲等,而Plusar中的broker和他們兩個有所不同,plusar中的broker是一個無狀態的節點,主要負責三件事情:
-
暴露REST接口用於執行管理員的命令以及topic所有者的查詢等
-
一個用於節點間通訊的異步的TCP服務器,協議目前采用的是Google之前開源的Protocol Buffer
-
為了支持地域復制,broker會將自己 集群所在的消息發布到其他可用區。
消息會被先發布到BookKeeper中,然后會在Broker本地內存中緩存一份,因此一般來說消息的讀取都會從從內存中讀取,因此第一條中所說的查找topic所有者就是說,因為BookKeeper中的一個ledger只允許一個writer,因此我們可以調用rest接口獲取到某一個topic當前的所有者。
BookKeeper
BookKeeper是一個可橫向擴展的、錯誤容忍的、低延遲的分布式存儲服務,BookKeeper中最基本的單位是記錄,實際上就一個字節數組,而記錄的數組稱之為ledger,BK會將記錄復制到多個bookies,存儲ledger的節點叫做bookies,從而獲得更高的可用性和錯誤容忍性。從設計階段BK就考慮到了各種故障,Bookies可以宕機、丟數據、臟數據,但是主要整個集群中有足夠的Bookies服務的行為就是正確的。
在Pulsar中,每個分區topic是由若干個ledger組成的,而ledger是一個append-only的數據結構,只允許單個writer,ledger中的每條記錄會被復制到多個bookies中,一個ledger被關閉后(例如broker宕機了或者達到了一定的大小)就只支持讀取,而當ledger中的數據不再需要的時候(例如所有的消費者都已經消費了這個ledger中的消息)就會被刪除.
Bookkeeper的主要優勢在於它可以保證在出現故障時在ledger的讀取一致性。因為ledger只能被同時被一個writer寫入,因為沒有競爭,BK可以更高效的實現寫入。在Broker宕機后重啟時,Plusar會啟動一個恢復的操作,從ZK中讀取最后一個寫入的Ledger並讀取最后一個已提交的記錄,然后所有的消費者也都被保證能看到同樣的內容。
我們知道Kafka在0.8版本之前是將消費進度存儲到ZK中的,但是ZK本質上基於單個日志的中心服務,簡單來講,ZK的性能不會隨着你增加更多的節點而線性增加,會只會相反減少,因為更多的節點意味着需要將日志同步到更多的節點,性能也會隨之下降,因此QPS也會受單機性能影響,因此0.8版本之后就將消費進度存儲到了Kafka的Topic中,而RocketMQ最初的版本也類似,有幾種不同的實現例如ZK、數據庫等,目前版本采用的是存儲到本機文件系統中,而Plusar采用了和Kafka類似的思想,Plusar將消費進度也存儲到了BK的ledger中。
元數據
Plusar中的元數據主要存儲到ZK中,例如不同可用區相關的配置會存在全局的ZK中,集群內部的ZK用於存儲例如某個topic的數據寫入到了那些Ledger、Broker目前的一些埋點數據等等
Plusar核心概念
Topic
發布訂閱系統中最核心的概念是topic,簡單來說,topic可以理解為一個管道,producer可以往這個管道丟消息,consumer可以從這個管道的另一端讀取消息,但是這里可以有多個consumer同時從這個管道讀取消息。
每個topic可以划分為多個分區,同一個topic下的不同分區所包含的消息都是不同的。每個消息在被添加到一個分區后都會分配一個唯一的offset,在同一個分區內消息是有序的,因此客戶端可以根據比如說用戶ID進行一個哈希取模從而使得整個用戶的消息都發往整個分區,從而一定程度上避免race condition的問題。
通過分區,將大量的消息分散到不同的節點處理從而獲得高吞吐。默認情況下,plusar的topic都是非分區的,但是支持通過cli或者接口創建一定分區數目的topic。
默認情況下Plusar會自動均衡Producer和Consumer,但有時候客戶端想要根據自己的業務規則也進行路由,Plusar默認支持以下幾種規則:單分區、輪詢、哈希、自定義(即自己實現相關接口來定制路由規則)
消費模式
消費決定了消息具體是如何被分發到消費者的,Plusar支持幾種不同的消費模式: exclusive、shared、failover。圖示如下:
-
Exclusive: 一個topic只能被一個消費者消費。Plusar默認就是這個模式
-
Shared: 共享模式或者叫輪詢模式,多個消費者可以連接到同一個topic,消息被依次分發給消費者,當一個消費者宕機或者主動斷開連接,那么發到那個消費者的還沒有ack的消息會得到重新調度分發給其他消費者。
-
Failover: 多個消費者可以連接同一個topic並按照字典序排序,第一個消費者會開始消費消息,稱之為master,當master斷開連接,所有未ack和隊列中剩下的消息會分發給另一個消費者。
Plusar目前也支持另一種Reader接口,支持傳入一個消息ID,例如說Message.Earliest來從最早的消息開始消費。
總結
Plusar作為下一代分布式消息隊列,擁有非常多吸引人的特性,也彌補了一些其他競品的短板,例如地域復制、多租戶、擴展性、讀寫隔離等等。