Apache RocketMQ 的 Service Mesh 開源之旅

頭圖.png

做者 | 凌楚   阿里巴巴開發工程師git

導讀:自 19 年末開始,支持 Apache RocketMQ 的 Network Filter 歷時 4 個月的 Code Review( Pull Request),於本月正式合入 CNCF Envoy 官方社區( RocketMQ Proxy Filter 官方文檔),這使得 RocketMQ 成爲繼 Dubbo 以後,國內第二個成功進入 Service Mesh 官方社區的中間件產品。

Service Mesh 下的消息收發

主要流程以下圖:github

1.png
圖 1數據庫

簡述一下 Service Mesh 下 RocketMQ 消息的發送與消費過程:編程

  • Pilot 獲取到 Topic 的路由信息並經過 xDS 的形式下發給數據平面/Envoy ,Envoy 會代理 SDK 向 Broker/Nameserver 發送的全部的網絡請求;
  • 發送時,Envoy 經過 request code 判斷出請求爲發送,並根據 topic 和 request code 選出對應的 CDS,而後經過 Envoy 提供的負載均衡策略選出對應的 Broker 併發送,這裏會使用數據平面的 subset 機制來確保選出的 Broker 是可寫的;
  • 消費時,Envoy 經過 request code 判斷出請求爲消費,並根據 topic 和 request code 選出對應的 CDS,而後和發送同樣選出對應的 Broker 進行消費(與發送相似,這裏也會使用 subset 來確保選出的 Broker 是可讀的),並記錄相應的元數據,當消息消費 SDK 發出 ACK 請求時會取出相應的元數據信息進行比對,再經過路由來準確將 ACK 請求發往上次消費時所使用的 Broker。

RocketMQ Mesh 化所遭遇的難題

Service Mesh 經常被稱爲下一代微服務,這一方面揭示了在早期 Mesh 化浪潮中微服務是絕對的主力軍,另外一方面,微服務的 Mesh 化也相對更加便利,而隨着消息隊列和一些數據庫產品也逐漸走向 Service Mesh,各個產品在這個過程當中也會有各自的問題亟需解決,RocketMQ 也沒有例外。網絡

有狀態的網絡模型

RocketMQ 的網絡模型比 RPC 更加複雜,是一套有狀態的網絡交互,這主要體如今兩點:併發

  • RocketMQ 目前的網絡調用高度依賴於有狀態的 IP;
  • 原生 SDK 中消費時的負載均衡使得每一個消費者的狀態不能夠被忽略。

對於前者,使得現有的 SDK 徹底沒法使用分區順序消息,由於發送請求和消費請求 RPC 的內容中並不包含 IP/(BrokerName + BrokerId) 等信息,致使使用了 Mesh 以後的 SDK 不能保證發送和消費的 Queue 在同一臺 Broker 上,即 Broker 信息自己在 Mesh 化的過程當中被抹除了。固然這一點,對於只有一臺 Broker 的全局順序消息而言是不存在的,由於數據平面在負載均衡的時候並無其餘 Broker 的選擇,所以在路由層面上,全局順序消息是不存在問題的。app

對於後者,RocketMQ 的 Pull/Push Consumer 中 Queue 是負載均衡的基本單位,原生的 Consumer 中實際上是要感知與本身處於同一 ConsumerGroup 下消費同一 Topic 的 Consumer 數目的,每一個 Consumer 根據本身的位置來選擇相應的 Queue 來進行消費,這些 Queue 在一個 Topic-ConsumerGroup 映射下是被每一個 Consumer 獨佔的,而這一點在現有的數據平面是很難實現的,並且,現有數據平面的負載均衡無法作到 Queue 粒度,這使得 RocketMQ 中的負載均衡策略已經再也不適用於 Service Mesh 體系下。負載均衡

此時咱們將目光投向了 RocketMQ 爲支持 HTTP 而開發的 Pop 消費接口,在 Pop 接口下,每一個 Queue 能夠再也不是被當前 Topic-ConsumerGroup 的 Consumer 獨佔的,不一樣的消費者能夠同時消費一個 Queue 裏的數據,這爲咱們使用 Envoy 中原生的負載均衡策略提供了可能。less

2.png
圖 2編程語言

圖 2 右側即爲 Service Mesh 中 Pop Consumer 的消費狀況,在 Envoy 中咱們會忽略掉 SDK 傳來的 Queue 信息。

彈內海量的 Topic 路由信息

在集團內部,Nameserver 中保存着上 GB 的 Topic 路由信息,在 Mesh 中,咱們將這部分抽象成 CDS,這使得對於沒法預先知道應用所使用的 Topic 的情形而言,控制平面只能全量推送 CDS,這無疑會給控制平面帶來巨大的穩定性壓力。

在 Envoy 更早期,是徹底的全量推送,在數據平面剛啓動時,控制平面會下發全量的 xDS 信息,以後控制平面則能夠主動控制數據的下發頻率,可是無疑下發的數據依舊是全量的。後續 Envoy 支持了部分的 delta xDS API,便可如下發增量的 xDS 數據給數據平面,這固然使得對於已有的 sidecar,新下發的數據量大大下降,可是 sidecar 中擁有的 xDS 數據依然是全量的,對應到 RocketMQ ,即全量的 CDS 信息都放在內存中,這是咱們不可接受的。因而咱們但願可以有 on-demand CDS 的方式使得 sidecar 能夠僅僅獲取本身想要的 CDS 。而此時正好 Envoy 支持了 delta CDS,並僅支持了這一種 delta xDS。其實此時擁有 delta CDS 的 xDS 協議自己已經提供了 on-demand CDS 的能力,可是不管是控制平面仍是數據平面並無暴露這種能力,因而在這裏對 Envoy 進行了修改並暴露了相關接口使得數據平面能夠主動向控制平面發起對指定 CDS 的請求,並基於 delta gRPC 的方式實現了一個簡單的控制平面。Envoy 會主動發起對指定 CDS 資源的請求,並提供了相應的回調接口供資源返回時進行調用。

對於 on-demand CDS 的敘述對應到 RocketMQ 的流程中是這樣的,當 GetTopicRoute 或者 SendMessage 的請求到達 Envoy 時,Envoy 會 hang 住這個流程併發起向控制平面中相應 CDS 資源的請求並直到資源返回後重啓這個流程。

關於 on-demand CDS 的修改,以前還向社區發起了 Pull Request ,如今看來當時的想法仍是太不成熟了。緣由是咱們這樣的作法徹底忽略了 RDS 的存在,而將 CDS 和 Topic 實現了強綁定,甚至名稱也如出一轍,關於這一點,社區的 Senior Maintainer [@htuch ]() 對咱們的想法進行了反駁,大意就是實際上的 CDS 資源名可能帶上了負載均衡方式,inbound/outbound 等各類 prefix 和 suffix,不能直接等同於 Topic 名,更重要的是社區賦予 CDS 自己的定義是脫離於業務的,而咱們這樣的作法過於 tricky ,是與社區的初衷背道而馳的。

所以咱們就須要加上 RDS 來進行抽象,RDS 經過 topic 和其餘信息來定位到具體所須要的 CDS 名,因爲做爲數據平面,沒法預先在代碼層面就知道所須要找的 CDS 名,那麼如此一來,經過 CDS 名來作 on-demand CDS 就更無從談起了,所以從這一點出發只能接受全量方案,不過好在這並不會影響代碼貢獻給社區。

route_config:
  name: default_route
  routes:
  - match:
      topic:
        exact: mesh
      headers:
        - name: code
          exact_match: 105
    route:
      cluster: foo-v145-acme-tau-beta-lambda

上面能夠看到對於 topic 名爲 mesh 的請求會被 RDS 路由到 foo-v145-acme-tau-beta-lambda 這個 CDS 上,事先咱們只知道 topic 名,沒法知道被匹配到的 CDS 資源名。

現在站在更高的視角,發現這個錯誤很簡單,可是其實這個問題咱們直到後續 code review 時才及時糾正,確實能夠更早就作得更好。

不過從目前社區的動態來看,on-demand xDS 或許已是一個 roadmap,起碼目前 xDS 已經全系支持 delta ,VHDS 更是首度支持了 on-demand 的特性。

Mesh 爲 RocketMQ 帶來了什麼?

A service mesh is a dedicated infrastructure layer for handling service-to-service communication. It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern, cloud native application. In practice, the service mesh is typically implemented as an array of lightweight network proxies that are deployed alongside application code, without the application needing to be aware.

這是 Service Mesh 這個詞的創造者 William Morgan 對其作出的定義,歸納一下:做爲網絡代理,並對用戶透明,承擔做爲基礎設施的職責。

3.png
圖 3

這裏的職責在 RocketMQ 中包括服務發現、負載均衡、流量監控等職責,使得調用方和被代理方的職責大大下降了。

固然目前的 RocketMQ Filter 爲了保證兼容性作出了不少讓步,好比爲了保證 SDK 能夠成功獲取到路由,將路由信息聚合包裝成了 TopicRouteData 返回給了 SDK ,可是在理想狀況下,SDK 自己已經不須要關心路由了,純爲 Mesh 情景設計的 SDK 是更加精簡的,再也不會有消費側 Rebalance,發送和消費的服務發現,甚至在將來像消息體壓縮和 schema 校驗這些功能 SDK 和 Broker 或許均可以不用再關心,來了就發送/消費,發送/消費完就走或許纔是 RocketMQ Mesh 的終極形態。

4.png
圖 4

What's Next ?

目前 RocketMQ Filter 具有了普通消息的發送和 Pop 消費能力,可是若是想要具有更加完整的產品形態,功能上還有一些須要補充:

  • 支持 Pull 請求:如今 Envoy Proxy 只接收 Pop 類型的消費請求,以後會考慮支持普通的 Pull 類型,Envoy 會將 Pull 請求轉換成 Pop 請求,從而作到讓用戶無感知;
  • 支持全局順序消息:目前在 Mesh 體系下,雖然全局順序消息的路由不存在問題,可是若是多個 Consumer 同時消費全局順序消息,其中一個消費者忽然下線致使消息沒有 ACK 而會致使另外一個消費者的消息產生亂序,這一點須要在 Envoy 中進行保證;
  • Broker 側的 Proxy:對 Broker 側的請求也進行代理和調度。

蜿蜒曲折的社區歷程

起初,RocketMQ Filter 的初次 Pull Request 就包含了當前幾乎所有的功能,致使了一個超過 8K 行的超大 PR,感謝@天千 在 Code Review 中所作的工做,很是專業,幫助了咱們更快地合入社區。

另外,Envoy 社區的 CI 實在太嚴格了,嚴格要求 97% 以上的單測行覆蓋率,Bazel 源碼級依賴,純靜態連接,自己無 cache 編譯 24 邏輯核心 CPU 和 load 均打滿至少半個小時才能編完,社區的各類 CI 跑完一次則少說兩三個小時,多則六七個小時,並對新提交的代碼有着極其嚴苛的語法和 format 要求,這使得在 PR 中修改一小部分代碼就可能帶來大量的單測變更和 format 需求,不過好的是單測能夠很方便地幫助咱們發現一些內存 case 。客觀上來講,官方社區以這麼高的標準來要求 contributors 確實能夠很大程度上控制住代碼質量,咱們在補全單測的過程當中,仍是發現並解決了很多自身的問題,總得來講仍是有必定必要的,畢竟對於 C++ 代碼而言,一旦生產環境出問題,調試和追蹤起來會困可貴多。

最後,RocketMQ Filter 的代碼由我和@叔田 共同完成,對於一個沒什麼開源經驗的我來講,爲這樣的熱門社區貢獻代碼是一次很是寶貴的經歷,同時也感謝叔田在此過程當中給予的幫助和建議。

相關連接

阿里巴巴雲原生中間件團隊招人啦

這裏有足夠多的業務場景、足夠大的消息生態、足夠深的分佈式技術等着你們前來探索,若是你知足:

  • 至少精通一種編程語言,Java 或 C++;
  • 深刻理解分佈式存儲理論,微服務優化實踐;
  • 計算機理論基礎紮實,例如對操做系統原理、TCP/IP 等有比較深刻的理解; 
  • 具備獨立設計一款生產環境高可用高可靠的中間件能力,例如 RocketMQ; 
  • 熟悉高併發、分佈式通訊、存儲、開源中間件軟件等相關技術者更佳。 

歡迎加入並參與新一代雲原生中間件建設!簡歷提交地址:yangkun.ayk@alibaba-inc.com。

課程推薦

爲了更多開發者可以享受到 Serverless 帶來的紅利,這一次,咱們集結了 10+ 位阿里巴巴 Serverless 領域技術專家,打造出最適合開發者入門的 Serverless 公開課,讓你即學即用,輕鬆擁抱雲計算的新範式——Serverless。

點擊便可免費觀看課程:https://developer.aliyun.com/learning/roadmap/serverless

阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的公衆號。」
相關文章
相關標籤/搜索