RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

技術瑣話發表於2019-03-19

RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

隨著網際網路金融業務和相關技術的不斷髮展,傳統金融行業為滿足業務快速發展需求,正在積極引入各類開源技術,以快速搶佔市場。那麼,以金融和科技作為雙驅動的平安銀行在開源技術的引入方面是如何評估,運用到哪些業務場景,以及面對複雜的網路環境,是如何去部署的呢?

本文將以 Apache RocketMQ 為例,和您一起瞭解平安銀行在開源技術選型方面的思考和實踐。

RocketMQ 在平安銀行的應用場景;

複雜網路環境下的部署實踐;

多隔離區場景下的部署情況;

多 IDC 場景下的部署情況;

改造實踐和遇到的小插曲

RocketMQ 在平安銀行的應用場景


目前,平安銀行透過 RocketMQ 解決了資料預加、資訊通知和狀態變化方面的業務需求,接下來,我們透過 App 登入、資產總覽和工資理財 3 個應用場景來展開講下。

App 登入:

當使用者開啟平安銀行 App 的時候,系統會根據使用者的登入 ID 去載入相應的使用者資料,比如銀行卡、信用卡和理財產品等,以及一些系統通知。這個場景下,我們用到了 RocketMQ 的非同步處理能力,即預載入需要使用的資料,提升使用者體驗。

資產總覽:

進入平安銀行 App 資產總覽的頁面,頁面顯示賬戶餘額、各類理財產品(黃金、基金和股票等),以及貸款等方面的資訊。平安銀行對接了各類基金、黃金和股票等來自不同金融主體、不同系統的資料,具有種類多、異構系統多和變化快的特點。我們的目標就是讓資產總覽資料儘可能準確,不同種類的資產變動的時候發出通知,資產系統收到通知後,根據變化的資料來計算出使用者當前的資產總覽。

工資理財:

工資理財是指每月工資下發到銀行卡後,系統可以實現自動買入使用者設定好的理財產品,例如買一些定投類的理財產品。這裡資訊的傳遞流程是:

RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

  • 銀行卡里的餘額出現變動,系統把變動資訊傳送到訊息引擎

  • Consumer 端進行消費,通知使用者賬戶已經出現變化;

  • 系統判斷變動是否來源於代發工資;

  • 如果是,系統會再傳送一條訊息;

  • 理財的 Consumer 進行消費;

  • 判斷現在是不是應該買入工資理財類的產品;

  • 如果是,自動買入使用者設定好的理財產品;

  • 自動買入之後,餘額再次變動,系統會再一次通知,這一次通知,判斷的就是一些其他的邏輯了。

那麼,在這些場景中,我們對訊息引擎會有哪些要求呢?

A、高可用、高可靠和高效能,這是金融行業引入開源技術的基本要求;

B、堆積能力,代發工資的使用者很多,一個公司的員工會在某個時間點集中發放;

C、順序能力,即賬戶變動在先,發出通知在後;

D、事務效能力,如果沒有事務性,有可能會出現賬戶變動了,但沒有觸發購買理財產品的情況;

E、重試和延遲訊息功能,比如工資發放的時候,可能是在晚上,這時候系統會自動把購買理財的動作放在第二天白天去操作,再發出通知;

F、訊息回溯能力,就是出現問題的時候,我們可以把這個訊息進行回溯,重新進行訊息的處理,提供完整的訊息軌跡;

在技術選型的過程中,RocketMQ 符合我們在這些典型使用場景中對訊息產品的需求,在引入的過程中,平安銀行也對社群做了相應的貢獻。


複雜網路環境下的部署實踐


多測試子環境下的服務呼叫場景

RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

平安銀行有多套測試子環境,用來對不同的feature進行測試,即圖中的 FAT、FAT001、FAT002、FAT003等。傳統銀行系統由大型機時代向更面向網際網路使用者的零售時代轉型過程中,不可避免微服務化,傳統較集中式系統會被劃分為較多的微服務,正常的情況如下圖,服務 A 呼叫服務 B,服務 B 呼叫服務 C,服務 C 呼叫服務 D。

隨著業務的需求,新的 feature,我們需要對服務 A 和 B 進行改動。相比在FAT環境裡去部署測試,更合適的方式是另起一套 FAT 環境,這裡我們命名為 FAT001,把服務A和B部署上去,A 呼叫 B,B會呼叫原來 FAT 環境裡的 C 和 D。

此時,另一個新的需求,需要對服務 A 和 C 進行改動。如果直接釋出到FAT 或 FAT001 肯定是不對的,會影響正在進行的測試,此時,我們會再起一套測試環境,命名為FAT002,釋出服務 A 和 C。由於 FAT002 裡沒有服務 B,所以服務A要呼叫服務 B 就需要去 FAT 環境(FAT 定義為較穩定的測試子環境)。服務 B 呼叫服務 C 的時候,就不應該呼叫本環境的 C了,而是調動 FAT002 的 C 才能實現測試功能。

再假設,系統同時還會有另外一個 feature 在測試 C 和 D,此時的呼叫邏輯也是一樣的,系統呼叫服務 A 和 B 的時候是在 FAT,呼叫服務 C 和 D 的時候會到 FAT003 的環境。

以上的服務呼叫場景是可以透過微服務框架解決的,進行全鏈路測試,但在生產環境中,使用者的真實請求比測試環境中會更復雜一些。

真實的使用者請求過程

我們看一下真實的使用者請求。

APP發起一個請求請求,進入閘道器,需要知道請求哪一個測試環境。通常的做法是:測試人員需要在APP上選好子環境,例如選擇 FAT001,我們可以直接把請求 FAT001 的閘道器(每個環境閘道器單獨部署),或者在requestheader上新增標識,讓閘道器去區分它來源於哪一個環境(閘道器統一部署)。假如閘道器判斷請求來源於 FAT002,那就會把分發給 FAT002環境進行處理。

訊息層面,如何處理這類使用者請求


以上是服務呼叫的請求路徑,比較好理解,但到了訊息佇列上,問題會變得複雜些,假如一個 feature 只是更改了消費者,那如何把這條訊息傳遞到改的消費者應用上去進行測試,而不被其它環境的消費者消費掉,這是我們需要去考慮的問題。 

RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

來看下具體的情況,叢集部署了 Broke A 和 Broke B,TopicA 分別部署在這兩個Broker上。 此時,Producer Group A 向 Topic A 中寫資料,Consumer Group A去消費,這種情況下是不會有任何問題。

但如果新增一套 FAT001 的環境,要求 FAT001 釋出的訊息,只能由 FAT001 來消費,FAT 不能消費,這種情況下我們該怎麼解決?

  • 在訊息上面加一些路由、或是加一些Tag、Filter、訊息的Property?

    這些都不能解決我們的問題。?‍♂️

  • 每個子環境部署一套 RocketMQ?

    一方面成本太高,另一方面如果這個feture測試完成了,需要把相關的應用再切回 FAT 進行處理,實現太過複雜。?‍♂️

我們想一下,多個 feature 同時進行測試,DB 會部署一套還是多套?

首先一個 feature 不會更改所在的應用,一般來說 DB 是部署一套的,在資料庫裡面新增欄位,來識別資料是來源於哪一個子環境,如果多套部署,不更改的應用取不到新部署的 DB 資料,無法進行全鏈路測試,所以同樣的,我們也沒有在每個子環境都部署一套 RocketMQ,而是部署統一部署,透過 RPC 路由把請求路由到正確的生產者集,改造訊息路由演算法把訊息路由到正確的消費者進行處理。

真實的使用者請求過程

RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

生產者變更

在上圖中生產者變更的場景下,預設的場景 FAT傳送,FAT 消費 ,沒有問題的,假設 FAT001 的生產者釋出了,需要 FAT001 傳送到MQ叢集,FAT 是可以直接消費。

RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

生產者、消費者同時變更

在上圖生產者和消費者同時變更的場景下,如果消費者在 FAT001也部署了應用,需要FAT消費者不能消費由FAT001產生的訊息,而是由 FAT001的消費者去消費。我們的處理方式是在邏輯上把Topic A下面的Queue進行分組,相當於加了邏輯分組,如果消費者在 FAT001 有部署,我們會把 Queue 的分組擴大,在其預設設定的情況下再翻一倍,新增的 Queue 就是給到 FAT001 進行消費的。

RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

只有消費者變更

再來看看只有消費者變更的場景,如上圖。

假設有個feature只需要更改消費者,部署在 FAT001。也是可以透過邏輯分組的方式,實現生產者根據請求來源來傳送訊息到佇列 FAT001 邏輯分組內的 Queue,從而只讓部署在 FAT001 的消費者消費。

透過以上 3 個場景,我們瞭解到新增邏輯分組的必要性,實現過程並不複雜。主要做了以下調整:?️

  • 這個邏輯分組什麼時候建立?

    新建 Topic 的時候,全部建好?還是 Consumer 上線/下線的時候動態的去進行調整?

我們選擇了動態建立的方式,這個過程中,我們新增了 Meta Server 進行後設資料管理,進行動態建立:

  • 新增 Meta Service,管理的後設資料包括 Producer、Consumer、Topic、Queue 和 Subenv等資訊:

  • 調整 Producer,取Request Head 裡面請求來源(FAT、FAT001、FAT002...),如果 Topic 對應的存在分組,選擇分組的 Queue,否則發到預設分組呢的Queue;

  • 調整 Consumer,上線時判斷應用部署的分組(FAT、FAT001、FAT002...),如果Topic不存在對應的分組,則新建;存在,則 rebalalce (新Consumer節點上線),下線時,判斷該分組是否還存在 其它Consumer例項,若不存在,刪除分組,否則 rebalalce(Consumer某一節點下線);

多隔離區場景下的部署實踐


由於對安全上的重視,金融行業的網路環境相比其他行業會更復雜。整個隔離區分為以下幾個部分:

RocketMQ 在多 IDC 場景以及多隔離區場景下的實踐

  • DMZ 區:

外網可以直接訪問,用於放置閘道器;

  • Web 區:

面向的是使用者手機,或者網頁上可以看到的功能應用;

  • 核心區:

包含核心的呼叫邏輯功能,和交易、訂單相關的核心應用,例如 DB 和儲存;

  • 外聯區:

用於訪問外網,有時候也會部署一些 Poxy 代理,因為內網不能直接訪問外網,需要透過代理去訪問外網;

  • 專用區域:

對接基金、三方存管等外部系統。在金融行業,如果某個系統是閉環的,那必須要去做隔離;

  • 管理區:

是指對整個區域的應用要進行集中管理,且資料流動是單向的,只能取資料,不能透過管理區把某區域的資料推送到另一區域。

此外,從安全的角度出發,所有的區域在生產環境下都透過防火牆進行隔離,這就給我們部署 RocketMQ 帶來了很大的實施難度。如果只部署一套,面對這麼多的防火牆,生產者消費者到叢集的的流量跨牆,會給網路帶來極大的不穩定,遇到瓶頸,防火牆幾乎無法線上平滑擴容;如果每個子環境都部署一套,又帶來運維複雜度,而且還是存在資料同步和跨牆消費的問題。

最終,我們採用的是折中的辦法,即統一部署加分隔離區部署,這樣做的益處是:☺️

  • 防火牆是開大策略,保證安全的前提下,符合監管要求;

  • 針對跨隔離區消費的問題,我們採用複製的方式,模擬消費者重新寫入目標叢集;

多IDC場景下的部署實踐


同城多IDC,可以認為近似區域網,比較好處理,但異地多IDC多活場景,目前我們還沒有特別好的解方案,多活不可避免面臨資料分片、資料合併和資料衝突的解決等問題。

如果 Topic 下資料有多活需求,我們暫時透過複製方式來處理。但這類手工模擬消費者消費資料寫入新叢集的複製方式,會存在一些問題,即複製到另一個叢集之後 offset 會改變,處理邏輯就會有偏差。我們透過 pull 的方式自定義的去根據 offset 去進行消費。當故障轉移到新的叢集需要去消費的時候,需要獲取到新叢集裡面正確的offset 值。此時,這個值和之前叢集裡的已經不一樣了,需要根據時間得到新叢集裡正確的offset 值,再去進行消費。在沒有更好的解決方案前,治理就顯得很關鍵了。

不過,我們注意到,在 RocketMQ 最新發布的版本里,提供了 DLedger 的特性,DLedger 定位的是一個工業級的 Java Library,可以友好地嵌入各類 Java 系統中,滿足其高可用、高可靠、強一致的需求。我們會盡快對這一特性進行整合和測試。

改造實踐和遇到的小插曲


我們在對 RocketMQ 的使用過程中,新增了以下功能或特性:?

A. 為生產者提供訊息的堆積能力。

B. 將所有配置管理部署到配置中心,並做雲端化處理,以滿足動態修改的需求。

C. 在 4.3 版本還未提供事務處理能力前,我們在本地資料庫裡去建一張訊息表,資料庫更改資料狀態的時候,會同步將資料寫入訊息表。若傳送失敗,則進行補償。並在客戶端裡進行封裝。

D. 實現統一的訊息者冪等處理。

E. 新增身份認證和訊息認證(注:RocketMQ 4.3 版本中已經實現身份認證功能)

當然,也遇到了一些小插曲,基本都是使用上的小問題可能大家也會碰到:?

A. 一個應用使用多個RocketMQ叢集時,未載入到正確的配置。Client 端,如果沒有對instancename 進行配置,一個應用連多個叢集會失敗。

B. 在大資料的場景下,記憶體溢位。訂閱的 Topic 越多,每個 Queue 在本地快取的 message 也會越多,預設每個 Queue 1000條,可能會把記憶體打爆,可根據實際情況調整。

C. 刪除資料時 IO 抖動,預設每天凌晨4點刪除資料,量上來後出現 IO 抖動,配置了訊息刪除策略,預設逗號分隔開,多配幾個時間刪除就可以了。

D. Broker上日誌報延遲訊息找不到資料檔案。在主備切換的演練過程中,出現了延遲訊息在Broker 上處理異常的情況。當主切換到備端時,延遲訊息在 Broker 上儲存的檔案被自動刪除,再切回主,由於延時訊息的後設資料感覺在,會查詢檔案進行處理,此時已找不到檔案。

E. 掛 NAS 的時候,IP 獲取了 NAS 的私網地址,並被提交給了服務端

以上就是我們在部署過程中遇到的一些小插曲,基本都是可以很快定位原因,解決的。

總的來看,RocketMQ 對平安銀行的訊息系統建設的幫助是非常大的,尤其是滿足了資料持久化、順序消費和回溯的需求,此外,在訊息的查詢方面,也比我們之前使用的訊息引擎好很多。最後再分享一點自己對中介軟體的一點感悟:中介軟體使用重在治理,規範不先行,開發兩行淚。

本文作者:

吳建峰,GitHub ID @devilfeng,來自平安銀行平臺架構部基礎框架團隊。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31562044/viewspace-2638789/,如需轉載,請註明出處,否則將追究法律責任。

相關文章