Pulsar:下一代消息引擎真的這麼強嗎?

背景

咱們最近在作新業務的技術選型,其中涉及到了對消息中間件的選擇;結合咱們的實際狀況但願它能知足如下幾個要求:架構

  • 友好的雲原生支持:由於如今的主力語言是 Go,同時在運維上可以足夠簡單。
  • 官方支持多種語言的 SDK:還有一些 PythonJava 相關的代碼須要維護。
  • 最好是有一些方便好用的特性,好比:延時消息、死信隊列、多租戶等。

固然還有一些水平擴容、吞吐量、低延遲這些特性就不用多說了,幾乎全部成熟的消息中間件都能知足這些要求。框架

基於以上的篩選條件,Pulsar 進入了咱們的視野。運維

做爲 Apache 下的頂級項目,以上特性都能很好的支持。ide

下面咱們來它有什麼過人之處。函數

架構

從官方的架構圖中能夠看出 Pulsar 主要有如下組件組成:工具

  1. Broker 無狀態組件,能夠水平擴展,主要用於生產者、消費者鏈接;與 Kafka 的 broker 相似,但沒有數據存儲功能,所以擴展更加輕鬆。
  2. BookKeeper 集羣:主要用於數據的持久化存儲。
  3. Zookeeper 用於存儲 brokerBookKeeper 的元數據。

總體一看彷佛比 Kafka 所依賴的組件還多,這樣確實會提供系統的複雜性;但一樣的好處也很明顯。spa

Pulsar 的存儲於計算是分離的,當須要擴容時會很是簡單,直接新增 broker 便可,沒有其餘的心智負擔。code

當存儲成爲瓶頸時也只須要擴容 BookKeeper,不須要人爲的作重平衡,BookKeeper 會自動負載。中間件

一樣的操做,Kafka 就要複雜的多了。對象

特性

多租戶

多租戶也是一個剛需功能,能夠在同一個集羣中對不一樣業務、團隊的數據進行隔離。

persistent://core/order/create-order

以這個 topic 名稱爲例,在 core 這個租戶下有一個 ordernamespace,最終纔是 create-ordertopic 名稱。

在實際使用中租戶通常是按照業務團隊進行劃分,namespace 則是當前團隊下的不一樣業務;這樣即可以很清晰的對 topic 進行管理。

一般有對比才會有傷害,在沒有多租戶的消息中間件中是如何處理這類問題的呢:

  1. 乾脆不分這麼細,全部業務線混着用,當團隊較小時可能問題不大;一旦業務增長,管理起來會很是麻煩。
  2. 本身在 topic 以前作一層抽象,但其實本質上也是在實現多租戶。
  3. 各個業務團隊各自維護本身的集羣,這樣固然也能解決問題,但運維複雜度天然也就提升了。

以上就很直觀的看出多租戶的重要性了。

Function 函數計算

Pulsar 還支持輕量級的函數計算,例如須要對某些消息進行數據清洗、轉換,而後再發布到另外一個 topic 中。

這類需求就能夠編寫一個簡單的函數,Pulsar 提供了 SDK 能夠方便的對數據進行處理,最後使用官方工具發佈到 broker 中。

在這以前這類簡單的需求可能也須要本身處理流處理引擎。

應用

除此以外的上層應用,好比生產者、消費者這類概念與使用你們都差很少。

好比 Pulsar 支持四種消費模式:

  • Exclusive:獨佔模式,同時只有一個消費者能夠啓動並消費數據;經過 SubscriptionName 標明是同一個消費者),適用範圍較小。
  • Failover 故障轉移模式:在獨佔模式基礎之上能夠同時啓動多個 consumer,一旦一個 consumer 掛掉以後其他的能夠快速頂上,但也只有一個 consumer 能夠消費;部分場景可用。
  • Shared 共享模式:能夠有 N 個消費者同時運行,消息按照 round-robin 輪詢投遞到每一個 consumer 中;當某個 consumer 宕機沒有 ack 時,該消息將會被投遞給其餘消費者。這種消費模式能夠提升消費能力,但消息沒法作到有序。
  • KeyShared 共享模式:基於共享模式;至關於對同一個topic中的消息進行分組,同一分組內的消息只能被同一個消費者有序消費。

第三種共享消費模式應該是使用最多的,當對消息有順序要求時可使用 KeyShared 模式。

SDK

官方支持的 SDK 很是豐富;我也在官方的 SDK 的基礎之上封裝了一個內部使用的 SDK

由於咱們使用了 dig 這樣的輕量級依賴注入庫,因此使用起來大概是這個樣子:

SetUpPulsar(lookupURL)
    container := dig.New()
    container.Provide(func() ConsumerConfigInstance {
        return NewConsumer(&pulsar.ConsumerOptions{
            Topic:            "persistent://core/order/create-order",
            SubscriptionName: "order-sub",
            Type:             pulsar.Shared,
            Name:             "consumer01",
        }, ConsumerOrder)

    })

    container.Provide(func() ConsumerConfigInstance {
        return NewConsumer(&pulsar.ConsumerOptions{
            Topic:            "persistent://core/order/update-order",
            SubscriptionName: "order-sub",
            Type:             pulsar.Shared,
            Name:             "consumer02",
        }, ConsumerInvoice)

    })

    container.Invoke(StartConsumer)

其中的兩個 container.Provide() 函數用於注入 consumer 對象。

container.Invoke(StartConsumer) 會從容器中取出全部的 consumer 對象,同時開始消費。

這時以我有限的 Go 開發經驗也在思考一個問題,在 Go 中是否須要依賴注入?

先來看看使用 Dig 這類庫所帶來的好處:

  • 對象交由容器管理,很方便的實現單例。
  • 當各個對象以前依賴關係複雜時,能夠減小許多建立、獲取對象的代碼,依賴關係更清晰。

一樣的壞處也有:

  • 跟蹤閱讀代碼時沒有那麼直觀,不能一眼看出某個依賴對象是如何建立的。
  • 與 Go 所推崇的簡潔之道不符。

對於使用過 SpringJava 開發者來講確定直呼真香,畢竟仍是熟悉的味道;但對於徹底沒有接觸過相似需求的 Gopher 來講貌似也不是剛需。

目前市面上各式各樣的 Go 依賴注入庫層出不窮,也不乏許多大廠出品,可見仍是頗有市場的。

我相信有不少 Gopher 很是反感將 Java 中的一些複雜概念引入到 Go,但我以爲依賴注入自己是不受語言限制,各類語言也都有本身的實現,只是 Java 中的 Spring 不只僅只是一個依賴注入框架,還有許多複雜功能,讓許多開發者望而生畏。

若是隻是依賴注入這個細分需求,實現起來並不複雜,並不會給帶來太多複雜度。若是花時間去看源碼,在理解概念的基礎上很快就能掌握。

回到 SDK 自己來講,GoSDK 現階段要比 Java 版本的功能少(準確來講只有 Java 版的功能最豐富),但核心的都有了,並不影響平常使用。

總結

本文介紹了 Pulsar 的一些基本概念與優勢,同時順便討論一下 Go 的依賴注入;若是你們和咱們同樣在作技術選型,不妨考慮一下 Pulsar

後續會繼續分享 Pulsar 的相關內容,有相關經驗的朋友也能夠在評論區留下本身的看法。

image.png

相關文章
相關標籤/搜索