您好,登錄后才能下訂單哦!
作者:個推平臺研發工程師 祥子
在個推的推送場景中,消息隊列在整個系統中占有非常重要的位置。
當 APP 有推送需求的時候, 會向個推發送一條推送命令,接到推送需求后,我們會把APP要求推送消息的用戶放入下發隊列中,進行消息下發;當同時有多個APP進行消息下發時,難免會出現資源競爭的情況, 因此就產生了優先級隊列的需求,在下發資源固定的情況下, 高優先級的用戶需要有更多的下發資源。
針對以上場景,個推基于 Kafka 設計了第一版的優先級隊列方案。Kafka 是 LinkedIn 開發的一個高性能、分布式消息系統;Kafka 在個推有非常廣泛的應用,如日志收集、在線和離線消息分發等。
架構
在該方案中,個推將優先級統一設定為高、中、低三個級別。具體操作方案如下:
對某個優先級根據 task (單次推送任務)維度,存入不同的 Topic,一個 task 只寫入一個 Topic,一個 Topic 可存多個 task;
Kafka 方案遇到的問題
隨著個推業務的不斷發展,接入的 APP 數量逐漸增多,第一版的優先級方案也逐漸暴露出一些問題:
基于上述問題,個推進行了新一輪的技術選型, 我們需要可以創建大量的 Topic, 同時吞吐性能不能比 Kafka 遜色。經過一段時間的調研,Apache Pulsar 引起了我們的關注。
Apache Pulsar 是一個企業級的分布式消息系統,最初由 Yahoo 開發,在 2016 年開源,并于2018年9月畢業成為 Apache 基金會的頂級項目。Pulsar 已經在 Yahoo 的生產環境使用了三年多,主要服務于Mail、Finance、Sports、 Flickr、 the Gemini Ads platform、 Sherpa (Yahoo 的 KV 存儲)。
架構
Topic 數量
Pulsar 可以支持百萬級別 Topic 數量的擴展,同時還能一直保持良好的性能。Topic 的伸縮性取決于它的內部組織和存儲方式。Pulsar 的數據保存在 bookie (BookKeeper 服務器)上,處于寫狀態的不同 Topic 的消息,在內存中排序,最終聚合保存到大文件中,在 Bookie 中需要更少的文件句柄。另一方面 Bookie 的 IO 更少依賴于文件系統的 Pagecache,Pulsar 也因此能夠支持大量的主題。
消費模型
Pulsar 支持三種消費模型:Exclusive、Shared 和Failover。
Exclusive (獨享):一個 Topic 只能被一個消費者消費。Pulsar 默認使用這種模式。
Shared(共享):共享模式,多個消費者可以連接到同一個 Topic,消息依次分發給消費者。當一個消費者宕機或者主動斷開連接時,那么分發給這個消費者的未確認(ack)的消息會得到重新調度,分發給其他消費者。
Failover (災備):一個訂閱同時只有一個消費者,可以有多個備份消費者。一旦主消費者故障,則備份消費者接管。不會出現同時有兩個活躍的消費者。
Exclusive和Failover訂閱,僅允許一個消費者來使用和消費每個訂閱的Topic。這兩種模式都按 Topic 分區順序使用消息。它們最適用于需要嚴格消息順序的流(Stream)用例。
Shared 允許每個主題分區有多個消費者。同一個訂閱中的每個消費者僅接收Topic分區的一部分消息。Shared最適用于不需要保證消息順序隊列(Queue)的使用模式,并且可以按照需要任意擴展消費者的數量。
存儲
Pulsar 引入了 Apache BookKeeper 作為存儲層,BookKeeper 是一個專門為實時系統優化過的分布式存儲系統,具有可擴展、高可用、低延遲等特性。具體介紹,請參考 BookKeeper官網。
Segment
BookKeeper以 Segment (在 BookKeeper 內部被稱作 ledger) 作為存儲的基本單元。從 Segment 到消息粒度,都會均勻分散到 BookKeeper 的集群中。這種機制保證了數據和服務均勻分散在 BookKeeper 集群中。
Pulsar 和 Kafka 都是基于 partition 的邏輯概念來做 Topic 存儲的。最根本的不同是,Kafka 的物理存儲是以 partition 為單位的,每個 partition 必須作為一個整體(一個目錄)存儲在某個 broker 上。 而 Pulsar 的 partition 是以 segment 作為物理存儲的單位,每個 partition 會再被打散并均勻分散到多個 bookie 節點中。
這樣的直接影響是,Kafka 的 partition 的大小,受制于單臺 broker 的存儲;而 Pulsar 的 partition 則可以利用整個集群的存儲容量。
擴容
當 partition 的容量達到上限后,需要擴容的時候,如果現有的單臺機器不能滿足,Kafka 可能需要添加新的存儲節點,并將 partition 的數據在節點之間搬移達到 rebalance 的狀態。
而 Pulsar 只需添加新的 Bookie 存儲節點即可。新加入的節點由于剩余空間大,會被優先使用,接收更多的新數據;整個擴容過程不涉及任何已有數據的拷貝和搬移。
Broker 故障
Pulsar 在單個節點失敗時也會體現同樣的優勢。如果 Pulsar 的某個服務節點 broker 失效,由于 broker 是無狀態的,其他的 broker 可以很快接管 Topic,不會涉及 Topic 數據的拷貝;如果存儲節點 Bookie 失效,在集群后臺中,其他的 Bookie 會從多個 Bookie 節點中并發讀取數據,并對失效節點的數據自動進行恢復,對前端服務不會造成影響。
Bookie 故障
Apache BookKeeper 中的副本修復是 Segment (甚至是 Entry)級別的多對多快速修復。這種方式只會復制必須的數據,這比重新復制整個主題分區要精細。如下圖所示,當錯誤發生時, Apache BookKeeper 可以從 bookie 3 和 bookie 4 中讀取 Segment 4 中的消息,并在 bookie 1 處修復 Segment 4。所有的副本修復都在后臺進行,對 Broker 和應用透明。
當某個 Bookie 節點出錯時,BookKeeper會自動添加可用的新 Bookie 來替換失敗的 Bookie,出錯的 Bookie 中的數據在后臺恢復,所有 Broker 的寫入不會被打斷,而且不會犧牲主題分區的可用性。
在設計思路上,Pulsar 方案和 Kafka 方案并沒有多大區別。但在新方案中,個推技術團隊借助 Pulsar 的特性,解決了 Kafka 方案中存在的問題。
dbStorage_rocksDB_blockCacheSize
設置的足夠大;當消息體量大,出現backlog 大量堆積時, 使用默認大小(256M)會出現讀耗時過大情況,導致消費變慢。backlogQuotaDefaultLimitGB
設置的足夠大(默認10G), 避免因為默認使用producer_request_hold
模式出現 block producer 的情況;當然可以根據實際業務選擇合適的 backlogQuotaDefaultRetentionPolicy
。現在, 個推針對優先級中間件的改造方案已經在部分現網業務中試運行,對于 Pulsar 的穩定性,我們還在持續關注中。
作為一個2016 年才開源的項目,Pulsar 擁有非常多吸引人的特性,也彌補了其他競品的短板,例如跨地域復制、多租戶、擴展性、讀寫隔離等。盡管在業內使用尚不廣泛, 但從現有的特性來說, Pulsar 表現出了取代 Kafka 的趨勢。在使用 Pulsar 過程中,我們也遇到了一些問題, 在此特別感謝翟佳和郭斯杰(兩位均為 Stream Native 的核心工程師、開源項目 Apache Pulsar 的 PMC 成員)給我們提供的支持和幫助。
參考文獻:
[1] 比拼 Kafka, 大數據分析新秀Pulsar 到底好在哪(https://www.infoq.cn/article/1UaxFKWUhUKTY1t_5gPq)
[2] 開源實時數據處理系統Pulsar:一套搞定Kafka+Flink+DB(https://juejin.im/post/5af414365188256717765441)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。