天天看點

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?
首發于個人公衆号 yatennosyo

企業中的不同的應用系統共同支撐起了業務的運作,在企業的發展過程中,總會有應用系統需要以設計時未曾想過的方式內建在一起。在過去二十年的實踐當中,消息傳遞技術通過使用消息同步兩個系統,同時又能夠解耦消息的發送者和接收者,很好地解決了這個問題。

說起企業級的消息平台,很容易想到 Kafka、RabbitMQ 和 RocketMQ 等等産品。但是近年來異軍突起的 Pulsar 正以超乎尋常的加速度進入開發者的視野,究其原因,是因為它在滾滾而來的雲原生浪潮當中最好地利用了雲原生的優勢。

雲原生浪潮

或許前兩年我們還能說雲原生是一個充滿希望的未來技術,但是如今雲原生已經滲透到了現代軟體開發的方方面面。雲原生不再隻是未來,而是既是現在,也是未來。

雲原生的雲是本地的擴充概念,傳統的應用必須直接跑在本地伺服器上,現在流行的應用還可以跑在本地或遠端的容器化的環境裡。

雲原生的原生即軟體設計之初就考慮到了将來會被運作在雲端的可能,進而在設計層面上就充分利用了雲資源的特點,典型的是分布式和彈性伸縮的能力。由于本地伺服器是雲的一個退化概念,雲原生的軟體也能自然的适配到傳統的部署模式上。

Pulsar 之是以說是雲原生的消息平台,核心就是它的架構設計能夠充分利用分布式的、能夠彈性伸縮的雲端資源。

Pulsar 的系統架構

典型的消息系統包括 Producer、Broker 和 Consumer 三個部分,其中關鍵性的角色是 Broker。正因為有了 Broker 承擔了消息無差别存儲和重新分發的責任,才使得消息的發送者和接收者能夠解耦。同時,Broker 接受和分發消息隻依賴于消息的格式,進而應用可以靈活地上線和下線生産者或消費者。

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

Pulsar 也是消息平台,是以它的整體架構也沒有超出這個架構。

然而,Pulsar 從存儲與計算分離的思想中得到啟發,獨特地把傳統消息平台中同時兼顧消息存儲和消息分發的 Broker 角色進一步拆分,分成專門處理消息存儲的 Bookie 部分和專門負責接收和分發消息的 Broker 部分,進而解放了 Broker 中維護本地狀态的職責。

同時,對存儲的形式做了多主複制的改造,結合上面的存儲與計算分離的拆分,真正做到了系統内所有同類型的節點之間的對等。

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

隻有做到節點對等,才能夠最大程度的利用雲存儲彈性伸縮的能力。

水準擴容

本節中我們分别讨論 Pulsar 消息平台上多個元件和消息主題(Topic)的水準擴容。

Pulsar 典型的消息傳遞模式是将消息按照 Topic 分類,Producer 發送消息時将指定這個消息是屬于哪個主題的,而 Consumer 訂閱消息時也是按照主題的粒度來訂閱消息的。

同一個 Topic 的消息以 Segment 的粒度被分散存儲在若幹個 Bookie 上,并有相應的備援系數。每一個 Topic 的消息收發隻能由單個 Broker 來承擔,這是為了保證一定的順序性而對吞吐量做出的權衡。當吞吐成為瓶頸時,可以采用 Partitioned Topic 技術來擴充同一個邏輯 Topic 下的實體 Topic 數量。是以,Pulsar 中的 Topic 概念更像 Kafka 中的 TopicPartition 概念。

下面,我們分别從 Broker、Bookie、Producer、Consumer 和 Topic 的角度來讨論 Pulsar 的水準擴容。

Broker

Pulsar 的 Server 端由 Broker 和 Bookie 組成,Broker 是收發消息的無狀态服務。

通常情況下,Topic 和 Bookie 的數量都是遠大于 Broker 的。

一方面,單個 Topic 所需的吞吐量一般不會占滿一個 Broker 執行個體,Pulsar能夠支援百萬級的 Topic 的生産消費,但現實中幾乎不存在百萬級的計算節點,千級萬級的計算節點已經是非常罕見的超級業務了。

另一方面,為了存儲海量的曆史資訊需要大量的 Bookie 節點,而消息即時性導緻曆史消息很少被消費。

Broker 的擴容場景往往是為了應對業務通路突增的情況,例如典型的電商業務大促。在這種場景,通過合理的設定消息保留時間,消息的存儲即 Bookie 的壓力可能并不是很大,單獨擴充 Broker 即可應對大量下遊活動 Consumer 的吞吐需求。

由于大部分場景下 Topic 是遠大于 Broker 的,是以我們不太需要考慮 Broker 大于 Topic 時擴充 Broker 不再對吞吐有效的場景。即使出現了這種情況,也可以通過新增 Partitioned Topic 來應對。

Broker 是無狀态的計算節點,它的擴容是平滑的。新的 Broker 節點上線後會将自己注冊到叢集中去,通過負載均衡算法擷取部分 Topic 的服務職責對外提供服務。

Bookie

Bookie 是負責存儲消息的有狀态服務,每個 Bookie 上以 Segment 的粒度存儲不同 Topic 的消息段。

Bookie 實際上是 BookKeeper 叢集的節點,BookKeeper 存儲消息段的中繼資料資訊并支援 Broker 根據相應的索引順序的通路消息内容,進而在邏輯上達到連續的消費消息隊列的效果。

Bookie 的擴容往往是在消息容量暴漲,同時消息保留時間無法在業務能忍受的範圍内進一步壓縮的情況。如果整個叢集每秒産生數個 GB 甚至 TB 的資料,怎麼能指望單個 Bookie 執行個體能夠扛下來呢?

有狀态的 Bookie 之是以在擴容的場景下能做到節點對等,是因為組成 Topic 的 Segment 透明地備援分布在多個 Bookie 節點上,同時,多個 Bookie 節點之間沒有主從之分。

新的 Bookie 節點上線以後會向 BooKeeper 叢集注冊自己。在其他所有外部環境沒有變更的情況下,在 BookKeeper 決定将新的 Segment 寫到哪個 Bookie 上的時候,根據負載均衡算法能夠自動的啟用新上線的 Bookie 來承擔這部分的存儲任務,進而緩解現有 Bookie 的壓力。前面提到叢集會管理 Segment 之間順序的中繼資料,是以這樣的負載均衡對應用端是無感覺的。

Kafka 要擴容存儲則完全不一樣。

由于 Kafka 限制單個 Partition 必須完整的存儲在同一個 Broker 上,同時 Partition 的備援是按照主從複制來實作的,這就導緻新的 Broker 節點上線之後,必須等待一段長時間的資料同步,直到把需要提供服務的 Partition 的資料都追趕上之後,通過重新觸發選舉讓新的節點成為相應 Partition 的主節點,才能開始對外服務。

這不僅僅是存儲的浪費,而且一次擴容會耗費很長的時間。下面的圖生動地展示了這兩者的不同。

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

關于存儲,值得一提的是 BookKeeper 對 I/O 做了細緻的抽象,區分了讀和寫的訪存路徑。隻要寫成功了就可以傳回 Producer 消息生産成功,而資料的排序和導入到讀盤是完全異步發生的。這樣本身就提高了寫的性能,同時還支援對讀寫的存儲獨立的進行配置,避免寫的瓶頸同時需要提升本已足夠的讀的配置。

Producer

Producer 的擴容很簡單,往往是生産者用戶端需要提高自己的吞吐。

Producer 的擴容沒有任何的依賴項,隻需要簡單的上線新節點就可以,新的節點将正常的連接配接到 Broker 并生産相應 Topic 的消息。

Consumer

Consumer 的擴容是一個比較 tricky 的事情,因為在 Pulsar 的模型裡這跟訂閱模式有關。

Pulsar 的消息消費是以 Subscription 的粒度來進行的,Subscription 的概念可以類比 Kafka 的 ConsumerGroup 的概念。

Pulsar 有四種不同的訂閱模式。

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

Exclusive 訂閱模式下,同一個 Subscription 裡隻有一個 Consumer 能消費 Topic,是以擴容會報錯。

就算是少量的 Consumer 節點以不同的 Subscription 身份訂閱大量的 Topic,希望通過上線新的 Consumer 以減少已有 Subscription 裡 Consumer 的負擔,也不會成功。

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

Failover 訂閱模式與 Exclusive 訂閱模式唯一的不同就是它允許同一個 Subscription 裡注冊不同的 Consumer。雖然同一個時刻隻會有一個 Consumer 在消費,但是如果 Consumer 發生異常,Subscription 裡的其他 Consumer 可以接替它繼續消費。

這種訂閱模式下擴容 Consumer 也是沒有作用的,因為新上線的 Consumer 隻能作為 standby 而不能立即開始承擔消費壓力。

可能一種直覺的想法是擴容後閃斷原來的 Consumer 以觸發 Consumer 的重新配置設定,但是考慮到閃斷重連的開銷,這完全是舍本逐末。

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

Shared 訂閱模式下,Topic 裡的消息會被均勻的分發到 Subscription 裡的各個 Consumer 裡,這種訂閱模式下顯然可以通過 Consumer 擴容來分擔消費壓力。

但需要注意的是,這種訂閱模式隻能保證消息被送達,而沒有任何的順序保證,需要應用層自己實作邏輯來排序。

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

Key-Shared 訂閱模式是 Pulsar 新實作的組合上面提到的訂閱模式優勢的一種新的訂閱模式,它保證相同 Key 的消息按順序被送到同一個 Consumer 上,同時又支援一個 Topic 被同一個 Subscription 裡的多個 Consumer 所消費。

這種訂閱模式下,Consumer 的擴容是 tricky 中的 tricky 動作。直覺的一個問題是,key 的配置設定應該怎麼變?

如果我們把 key 對應到 Kafka 裡的 Partition Key,那麼這個過程在 Kafka 裡是通過 Consumer rebalance 來實作的。然而, Consumer 端的同步是緩慢的,Consumer rebalance 也是 Kafka 最令使用者頭疼的場景之一。

Pulsar 采用了另一種方式來解決這個問題。

首先,Pulsar 判斷将某個 key 對應的消息發送到哪個 Consumer 上的做法是通過 hash 後分桶來實作的。

預設政策下,新上線的 Consumer 會加入到原來的分桶組裡,根據配置選擇直接切分原來的分桶給新的 Consumer 騰出位置,或者使用一緻性哈希的政策來挪位置。

這裡一個重要的點是由 Server 端來識别新上線的 Consumer,并負責将已經送出的消息繼續送達到之前選擇的 Consumer,而之後的消息按照新的分桶來選擇 Consumer。實際上,Kafka 的 Consumer rebalance 很大一部分就是為了同步 Consumer 的狀态避免一份消息送到兩個 Consumer 上或者丢失。

Pulsar 還提供了固定 Hash 範圍的政策,可以根據使用者代碼指定某個 Consumer 消費某個 Hash 範圍的消息。在這種政策下,新上線的 Consumer 無法取得合法的 Hash 範圍,是以不能做 Consumer 擴容。或者說,新上線 Consumer 後改變固定政策,需要整體重新開機才能生效。

Topic

Topic 從概念上說是互相獨立的,是以擴容本來也不應該成為一個問題,但是在 Partitioned Topic 場景下作為對标 Kafka TopicPartition 的概念還是有擴容的可能性的。

雖然如此,Pulsar 裡 Topic 的新增仍然是一個很自然的非常獨立的動作。

對于采用通配符訂閱的 Consumer 來說,這個新上線的 Topic 被比對到就會被嘗試訂閱。如果沒有這樣的 Consumer,則需要專門起一個 Consumer 來消費這個新增的 Topic。

對于向 Topic 中生産消息的 Producer 來說,哪些消息要生産到新上線的 Topic 裡,則是由路由模式來決定的。類似于訂閱模式,不同的路由模式有不同的順序保證,這裡就不做展開了。

容錯

彈性伸縮的另一個方面是關于應用的優雅容錯。

Pulsar 的系統對不同功能的元件做了邊界明确的拆分,各個元件可以獨立的容錯,這也是其雲原生特性之一。

容錯其實跟縮容有些相似。一般來說,安全節點切換是先擴容再縮容,而容錯場景則類似于縮容後再擴容。

是以,對比上面的五個主題,我們可以分别讨論容錯。但是,其中隻有 Broker 和 Bookie 的容錯是不平凡的。

Producer 的容錯是純用戶端的容錯,與 Pulsar 無關。

Consumer 的容錯首先是用戶端的容錯,其次對應的行為與訂閱模式有關。根據上面對不同訂閱模式擴容的描述不難反推出來。

Topic 是一個抽象概念,沒有容錯一說。下線 Topic 等效于删掉對應的資料,這是業務決定而不是系統可以處理的問題。

Broker

Broker 是無狀态的服務,它發生故障的時候最主要要做的是把它負責收發新的 Topic 交給其他 Broker 來接手。

Pulsar 叢集的 Broker 會周期性的擷取新的 Topic,一個失去負責人的 Topic 也能被作為新的 Topic 發現。是以故障的 Broker 所負責的 Topic 将在一段時間後被新的 Broker 所接管,這個時間是根據經驗配置的。

因為 Broker 本身不存儲 Topic 的消費情況,也不存儲 Topic 與 Segment 的對應關系,這些資訊都存儲在 BookKeeper 上,是以新接手的 Broker 能夠快速的從 BookKeeper 中恢複相應的狀态并恢複 Topic 對外的消息收發。

整個過程用戶端可能會有抖動,但是無需做任何響應,也就是應用無感覺的。同時,因為 Broker 不存儲狀态,是以也沒有需要 catch up 的資料。這跟 Kafka 在 Broker 挂掉之後需要等待選主和主題分區消息同步是不同的。

Bookie

Bookie 是有狀态的服務,它的優雅容錯主要依賴于節點對等。

上面我們提到 Bookie 的節點對等是因為組成 Topic 的 Segment 透明地備援分布在多個 Bookie 節點上,容錯場景下,除了這一點還要強調 BookKeeper 采用的是多主複制的備援方式,是以沒有選主的流程。每個存儲了相應 Segment 的 Bookie 都可以對等的對外提供服務。

是以,隻要應用選擇每個消息寫出若幹份的複制,在隻有一個 Bookie 節點挂掉的情況下,剩餘的存有相應消息的 Bookie 可以繼續對外提供服務。進而達到應用對 Bookie 的故障無感覺。

當然,BookKeeper 也不會對 Bookie 發生故障不做理會,而是會有背景線程周期性的檢查 Segment 的備援度是否符合配置數目。Bookie 挂掉的情況下,備援度不足,BookKeeper 的修複程序就會從其他 Bookie 上複制一份資料到另一個 Bookie 上維持備援度。

這個過程又是異步的,是以它的檢查間隔和修複政策包括對應機器的配置又可以單獨保障,做到資料恢複是可控的。

這裡需要提一下的是,很多分布式系統的新開發者,會像我剛接觸這些概念的時候一樣,疑惑那如果我所有的備援全部一起挂掉了,那怎麼辦?

簡短的回答是那資料就丢掉了,因為持久化并不能保證你的資料變成概念永存。

但是實際情況不會這麼糟糕。

首先,今天的機器不會那麼的不可靠,同時發生問題的機率微乎其微。雖然挂掉某一台甚至某幾台機器在生産實踐中幾乎每天甚至每個小時都在發生,但是你的幾份複制同時機率的機率非常低。這個事情需要靠 SLA 來保證和追責。

其次,可以通過增加複制分數來進一步減少全部故障的機率,但是對應的,寫入如此之多的複制造成的資源浪費和延時增加是不可避免的。

最後,萬一真的碰上自然災害一類的不可抗力,那麼你可以通過禁寫或者停止服務首先保護自己,在災後嘗試從硬碟裡恢複資料。或者換個方向考慮做異地災備。如果實在是巧了又巧,所有備份所在地一起爆炸,你的資料盤被挫骨揚灰,那隻能兩手一攤,沒啥辦法了。

雲上的 Pulsar

Pulsar 的元件隔離和節點對等特性使得它可以原生地運作在雲端環境。

本節以 Pulsar on Kubernetes 為例,簡單的介紹這些元件如何部署到雲端上。

因為 Producer 和 Consumer 是用戶端,實際上 Pulsar 叢集并不需要關心它們的部署,是以實際需要部署的是 Broker 和 Bookie。

Kubernetes 上部署是基于資源展開的,我們看看 Broker 和 Bookie 分别對應到哪種資源。

Broker 作為無狀态的節點,ReplicaSet 直接開沖。

Bookie 是有狀态的節點,但是節點之間是對等的,可以采用 StatefulSet 來部署。

這裡隐藏的是實際存儲資料的硬碟,在 Kubernetes 的世界裡可以對應到 PersistentVolume 資源。

什麼是雲平台_為什麼說 Pulsar 是雲原生的消息平台?

如何挑戰現有系統?

最後這一節是私貨,主要以 Pulsar 做例子聊一聊一個新系統如何挑戰現有系統。

首先,Pulsar 是開源軟體。開源實際上并不僅僅是情懷,它還有着強大的商業和社會力量。

要想挑戰現有系統,首當其沖的是需要讓使用者知道你的新系統。閉源産品要麼花費大量的資金做宣傳,要麼耗費大量的人力挨家挨戶的推銷。開源産品也需要宣傳,但是它的完整版本是公開的,你可以直接取用,并且借力開源社群的影響力快速推廣你的産品。俗話說,酒香也怕巷子深。開源就是把酒搬到路邊來賣,搬到集市來賣。雖然使用者仍然需要主動的選中,但是整個過程的負擔無疑是大幅降低的。

要想挑戰現有系統,還需要有多層次的技術人才。項目開源出來在協作平台上,全世界的研發人員都可以來做貢獻,幫助項目修複問題、完善文檔和添加功能。

這裡先插一句項目和貢獻者應該互利共赢、共同發展,而不是某些項目開源當大爺,使喚人來做貢獻。

話說回來,這裡提到的研發人員并沒有強調是高手或者專家,或者投入時間的程度。實際上,我們需要大量的不同層次的貢獻者來做從頂層設計到基礎設施所有層次的工作。

使用者從現有系統遷移到新系統是有成本的,最直接的就是新系統因為環境問題運作不起來,現有系統的 API 和新系統的 API 不相容,要做原來做過的事,總結過的經驗和最佳實踐,不知道怎麼做。

Pulsar 社群有多層次的貢獻者和愛好者,能夠在郵件清單、論壇、微信群聊以及線下會面等多種場合解決潛在使用者多種層次的疑問和困難。當然這麼說有些誇張,但是社群的形式所能表現出來的最佳效果就是這樣的。

Pulsar 社群同時還實作了其他競品消息系統的協定。StreamNative 公司的員工作為 Pulsar 社群的重要組成,開發了 Kafka on Pulsar 以支援存量最大的 Kafka 使用者平滑的進行遷移;中國移動雲能力中心的員工在社群成員的幫助下主導了 AMQP on Pulsar 的開發,支援豐富類型的 AMQP 協定的 MQ 産品使用者的遷移。

這一點實際上是很多新系統會選擇的道路,不僅僅是薅存量使用者的想法,一點突破,其他持平。還有一點很重要的是保持自己在正确的市場方向上,做現在最成熟的協定,落實它的功能,而在實作上做出差異,這樣你至少不會錯誤地開發實際上不存在的需求。

開源軟體以社群(community)為運作核心,一方面從人的粒度做潛移默化的訓練(trainning)培養所有層次的人才解決使用者遇到的各種問題,另一方面以項目的粒度完善系統的生态系統(ecosystem)。當你的系統擁有龐大的使用者群體和支援群體,同時業内能遇到的挑戰幾乎都有生态系統内的解決方案的時候,毫無疑問,現有系統被取代隻是時間問題。因為喜新厭舊是人性,沒有非要使用舊的理由,新一代成長之後,就會使用新的技術。