硬核測試:Pulsar 與 Kafka 在金融場景下的性能分析
背景
Apache Pulsar 是下一代分布式消息流平台,采用計算存儲分層架構,具備多租戶、高一緻、高性能、百萬 topic、資料平滑遷移等諸多優勢。越來越多的企業正在使用 Pulsar 或者嘗試将 Pulsar 應用到生産環境中。
騰訊把 Pulsar 作為計費系統的消息總線來支撐千億級線上交易。騰訊計費體量龐大,要解決的核心問題就是必須確定錢貨一緻。首先,保證每一筆支付交易不出現錯賬,做到高一緻、高可靠。其次,保證計費承載的所有業務 7*24 可用,做到高可用、高性能。計費消息總線必須具備這些能力。
Pulsar 架構解析
在一緻性方面,Pulsar 采用 Quorum 算法,通過 write quorum 和 ack quorum 來保證分布式消息隊列的副本數和強一緻寫入的應答數(A>W/2)。在性能方面,Pulsar 采用 Pipeline 方式生産消息,通過順序寫和條帶化寫入降低磁盤 IO 壓力,多種緩存減少網絡請求加快消費效率。
Pulsar 性能高主要展現在網絡模型、通信協定、隊列模型、磁盤 IO 和條帶化寫入。下面我會一一詳細講解。
網絡模型
Pulsar Broker 是一個典型的 Reactor 模型,主要包含一個網絡線程池,負責處理網絡請求,進行網絡的收發以及編解碼,接着把請求通過請求隊列推送給核心線程池進行處理。首先,Pulsar 采用多線程方式,充分利用現代系統的多核優勢,把同一任務請求配置設定給同一個線程處理,盡量避免線程之間切換帶來的開銷。其次,Pulsar 采用隊列方式實作了網絡處理子產品及核心處理子產品的異步解耦,實作了網絡處理和檔案 I/O 并行處理,極大地提高了整個系統的效率。
通信協定
資訊(message)采用二進制編碼,格式簡單;用戶端生成二進制資料直接發送給 Pulsar 後端 broker,broker 端不解碼直接發送給 bookie 存儲,存儲格式也是二進制,是以消息生産消費過程沒有任何編解碼操作。消息的壓縮以及批量發送都是在用戶端完成,這能進一步提升 broker 處理消息的能力。
隊列模型
Pulsar 對主題(topic)進行分區(partition),并盡量将不同的分區配置設定到不同的 Broker,實作水準擴充。Pulsar 支援線上調整分區數量,理論上支援無限吞吐量。雖然 ZooKeeper 的容量和性能會影響 broker 個數和分區數量,但該限制上限非常大,可以認為沒有上限。
磁盤 IO
消息隊列屬于磁盤 IO 密集型系統,是以優化磁盤 IO 至關重要。Pulsar 中的磁盤相關操作主要分為記錄檔和資料日志兩類。記錄檔用于資料恢複,采用完全順序寫的模式,寫入成功即可認為生産成功,是以 Pulsar 可以支援百萬主題,不會因為随機寫而導緻性能急劇下降。
記錄檔也可以是亂序的,這樣可以讓記錄檔寫入保持最佳寫入速率,資料日志會進行排序和去重,雖然出現寫放大的情況,但是這種收益是值得的:通過将記錄檔和資料日志挂在到不同的磁盤上,将讀寫 IO 分離,進一步提升整個系統 IO 相關的處理能力。
條帶化寫入
條帶化寫入能夠利用更多的 bookie 節點來進行 IO 分擔;Bookie 設定了寫緩存和讀緩存。最新的消息放在寫緩存,其他消息會批量從檔案讀取加入到讀緩存中,提升讀取效率。
從架構來看,Pulsar 在處理消息的各個流程中沒有明顯的卡點。記錄檔持久化隻有一個線程來負責刷盤,可能會造成卡頓。根據磁盤特性,可以設定多塊盤,多個目錄,提升磁盤讀寫性能,這完全能夠滿足我們的需求。
測試
在騰訊計費場景中,我們設定相同的場景,分别對 Pulsar 和 Kafka 進行了壓測對比,具體的測試場景如下。
壓測資料如下:
以上資料可以看到,網絡 IO 方面,3 個副本多分區的情況下,Pulsar 幾乎要把 broker 網卡出流量跑滿,因為一份資料需要在 broker 端分發 3 次,這是計算存儲分離的代價。
Kafka 的性能資料有點讓人失望,整體性能沒有上去,這應該和 Kafka 本身的副本同步機制有關:Kafka 采用的是 follow 同步拉取的政策,導緻整體效率并不高。
延遲方面,Pulsar 在生産端表現更優越些,當資源沒有到達瓶頸時,整個時耗 99% 在 10 毫秒以内,在垃圾回收(Garbage Collection,GC)和建立記錄檔檔案時會出現波動。
從壓測的結果來看,在高一緻的場景下,Pulsar 性能優于 Kafka。如果設定 log.flush.interval.messages=1 的情況,Kafka 性能表現更差,kafka 在設計之初就是為高吞吐,并沒有類似直接同步刷盤這些參數。
此外,我們還測試了其他場景,比如百萬 Topic 和跨地域複制等。在百萬 Topic 場景的生産和消費場景測試中,Pulsar 沒有因為 Topic 數量增長而出現性能急劇下降的情況,而 Kafka 因為大量的随機寫導緻系統快速變慢。
Pulsar 原生支援跨地域複制,并支援同步和異步兩種方式。Kafka 在同城跨地域複制中,吞吐量不高,複制速度很慢,是以在跨地域複制場景中,我們測試了 Pulsar 同步複制方式,存儲叢集采用跨城部署,等待 ACK 時必須包含多地應答,測試使用的相關參數和同城一緻。測試結果證明,在跨城情況下,Pulsar 吞吐量可以達到 28萬QPS。當然,跨城跨地域複制的性能很大程度依賴于目前的網絡品質。
可用性分析
作為新型分布式消息流平台,Pulsar 有很多優勢。得益于 bookie 的分片處理以及 ledger 選擇存儲節點的政策,運維 Pulsar 非常簡單,可以擺脫類似 Kafka 手動平衡資料煩擾。但 Pulsar 也不是十全十美,本身也存在一些問題,社群仍在改進中。
Pulsar 對 ZooKeeper 的強依賴
Pulsar 對 ZooKeeper 有很強的依賴。在極限情況下,ZooKeeper 叢集出現當機或者阻塞,會導緻整個服務當機。ZooKeeper 叢集奔潰的機率相對小,畢竟 ZooKeeper 經過了大量線上系統的考驗,使用還是相對廣泛的。但 ZooKeeper 堵塞的機率相對較高,比如在百萬 Topic 場景下,會産生百萬級的 ledger 中繼資料資訊,這些資料都需要與 ZooKeeper 進行互動。
例如,建立一次主題(topic),需要建立主題分區中繼資料、Topic 名、Topic 存儲 ledger 節點;而建立一次 ledger 又需要建立和删除唯一的 ledgerid 和 ledger 中繼資料資訊節點,一共需要 5 次 ZooKeeper 寫入操作,一次訂閱也需要類似的 4 次 ZooKeeper 寫入操作,是以總共需要 9 次寫入操作。如果同時集中建立百萬級的主題,勢必會對 ZooKeeper 造成很大的壓力。
Pulsar 具有分散 ZooKeeper 部署的能力,能夠在一定程度上緩解 ZooKeeper 的壓力,依賴最大的是 zookeeperServer 這個 ZooKeeper 叢集。從之前的分析來看,寫操作相對可控,可以通過控制台建立 Topic。bookie 依賴的 ZooKeeper 操作頻率最高,如果該 ZooKeeper 出現阻塞,目前寫入并不會造成影響。
可以按照同樣的思路優化對 zookeeperServerzk 的依賴。至少對于目前的服務可以持續一段時間,給 ZooKeeper 足夠的時間進行恢複;其次減少 ZooKeeper 的寫入次數,隻用于必要的操作,比如 broker 選舉等。像 broker 的負載資訊,可以尋求其他存儲媒體,尤其是當一個 broker 服務大量主題時,這個資訊會達到兆(M)級别。我們正在和 Pulsar 社群攜手優化 broker 負載功能。
Pulsar 記憶體管理稍複雜
Pulsar 的記憶體由 JVM 的堆記憶體和堆外存構成,消息的發送和緩存通過堆外記憶體來存儲,減少 IO 造成的垃圾回收(GC);堆記憶體主要緩存 ZooKeeper 相關資料,比如 ledger 的中繼資料資訊和訂閱者重推的消息 ID 緩存資訊,通過 dump 記憶體分析發現,一個 ledger 中繼資料資訊需要占用約 10K,一個訂閱者者重推消息 ID 緩存初始為 16K,且會持續增長。當 broker 的記憶體持續增長時,最終頻繁進行整體垃圾回收(full GC),直到最終退出。
要解決這個問題,首先要找到可以減少記憶體占用的字段,比如 ledger 中繼資料資訊裡面的 bookie 位址資訊。每個 ledger 都會建立對象,而 bookie 節點非常有限,可以通過全局變量來減少建立不必要的對象;訂閱者重推消息 ID 緩存可以把初始化控制在 1K 内,定期進行縮容等。這些操作可以大大提升 Broker 的可用性。
和 Kafka 相比,Pulsar broker 的優點比較多,Pulsar 能夠自動進行負載均衡,不會因為某個 broker 負載過高導緻服務不穩定,可以快速擴容,降低整個叢集的負載。
總結
總體來說,Pulsar 在高一緻場景中,性能表現優異,目前已在騰訊内部廣泛使用,比如騰訊金融和大資料場景。大資料場景主要基于 KOP 模式,目前其性能已經非常接近 Kafka,某些場景甚至已經超越 Kafka。我們深信,在社群和廣大開發愛好者的共同努力下,Pulsar 會越來越好,開啟下一代雲原生消息流的新篇章。
本文作者:劉德志
騰訊專家工程師、TEG 技術工程事業群和計費系統開發者