視覺化服務編排在金融APP中的實踐

語言: CN / TW / HK

本文重點介紹了京東金融APP在BFF層實踐過程中遇到的問題,並引出視覺化服務編排在金融APP中的落地實踐,其中重點介紹了視覺化服務編排系統的核心功能及實現。視覺化服務編排系統已經穩定支援了金融APP從去年618到現在的所有發版迭代,對人效提升幫助明顯,希望能夠對大家在BFF的實踐有參考意義。讀者通過這篇文章可以瞭解到基於傳統編碼方式來實現業務需求時遇到的問題和挑戰,以及通過“視覺化服務編排”如何規避及解決之前遇到的問題。

 

01

前言

在今年的敏捷團隊建設中,我通過Suite執行器實現了一鍵自動化單元測試。Juint除了Suite執行器還有哪些執行器呢?由此我的Runner探索之旅開始了!

隨著SOA架構的提出到微服務架構的落地實踐,原本在同一個系統內執行的業務被拆分到了不同的系統或服務中。這樣做,在增加業務架構靈活性的同時,也給端上的呼叫帶來了更多的複雜性,如:原本一次請求即可處理完成的業務,現在可能需要多次請求才能完成。為了降低端上邏輯的複雜性並提高前後端互動效率,BFF層應運而生。

BFF作為前後端的代理層,為端上的應用提供了一個業務介面聚合層,它遮蔽了複雜的服務呼叫關係,讓端上應用可以聚焦在所需要的資料上,而不用關心提供資料的具體服務。但BFF實踐的過程中,也遇到了很多問題和挑戰,如BFF層的需求往往比較簡單,但通過硬編碼的方式實現,流程非常繁瑣且效率低,那如何提高BFF層需求的交付效率,便是目前需要重點關注解決的問題。

 

02

BFF實踐中的問題

理解,首先 MCube 會依據模板快取狀態判斷是否需要網路獲取最新模板,當獲取到模板後進行模板載入,載入階段會將產物轉換為檢視樹的結構,轉換完成後將通過表示式引擎解析表示式並取得正確的值,通過事件解析引擎解析使用者自定義事件並完成事件的繫結,完成解析賦值以及事件繫結後進行檢視的渲染,最終將目標頁面展示到螢幕

BFF(Backend For Frontend), 即服務於前端的後端,可看做是一個後端服務的代理層,它主要做介面聚合和響應資料裁剪。這裡需要指出的是:BFF 只是架構分層中引入的一個概念,而非一種技術。

BFF層的核心職責是為前端(包括原生、小程式、H5等)適配不同的業務場景,降低客戶端與業務端的耦合,前期通過硬編碼的方式來實現BFF層的需求,是最簡單最直接的方式。但隨著BFF層承接業務需求的增多,通過編碼的方式也逐漸暴露出一些問題,如編碼效率低、編碼細節難以規範、除錯測試效率低和服務治理能力弱等。

2.1 編碼效率低

在接到一個新的業務需求,除了前期的需求溝通外,開始編碼前,通常還需要做一些準備工作,對於Java應用來說,流程大概是這樣的:

 

整個流程中,有太多需要人工處理及等待的步驟,這將會大大降低整個研發流程的效率,雖然現在有一些CI/CD的工具可以減少部分等待時間,但整體的編碼體驗及效率上的問題還是得不到根本的解決。

2.2 編碼細節難以規範

由BFF層的特點決定,其承接的需求大多是對業務介面進行整合輸出,包括對多個介面的呼叫、對返回資料進行裁剪、排序、格式化等操作。單看介面的呼叫方式就有多種實現,如並行呼叫、序列呼叫等,為了降低服務的響應時間和提高系統性能及吞吐量,多個無依賴關係的介面我們通常會採用並行呼叫的方式實現。並行呼叫,我們可以通過執行緒池實現,也可以通過事件回撥的方式實現,通過事件回撥相對於執行緒池的實現會有更高的效能和穩定性,但實現起來也會更復雜,研發同學通常都會選擇更簡單執行緒池實現。

2.3 除錯測試效率低

雖然市面上目前有很多單元測試的工具和框架,但使用起來都少不了配置和編碼環節。只要有功能新增或修改,我們就要編寫對應的單元測試程式碼,另外單元測試程式碼執行大多需要啟動整個應用,而應用的啟動通常都是分鐘級的,這就導致我們研發效率進一步降低。

此外,開發環境中,我們依賴的業務介面通常是部署測試環境的,但測試環境經常會有部署、重啟的操作,甚至有些介面都沒有測試環境,這就對我們研發除錯帶來了更多不便。

2.4 服務治理能力弱

程式碼本質上是非結構化的文字資料,我們很難基於程式碼進行統計,尤其是大促備戰前,我們需要知道某個業務方的介面都被哪些服務引用或被哪些頁面呼叫了,此時介面和服務間的依賴關係就顯得尤為重要,但基於編碼的方式我們是很難做到精準統計,雖然有一些呼叫鏈追蹤工具可以提供幫助,但還是不夠直接,還是需要人肉的去做進一步的識別。

 

03

視覺化服務編排

理解,首先 MCube 會依據模板快取狀態判斷是否需要網路獲取最新模板,當獲取到模板後進行模板載入,載入階段會將產物轉換為檢視樹的結構,轉換完成後將通過表示式引擎解析表示式並取得正確的值,通過事件解析引擎解析使用者自定義事件並完成事件的繫結,完成解析賦值以及事件繫結後進行檢視的渲染,最終將目標頁面展示到螢幕。

視覺化服務編排的提出,就是為了解決上面提到的問題。視覺化服務編排的初衷是希望儘可能地拋棄程式碼,通過線上視覺化拖拽的方式完成功能的開發、除錯、測試和上線,我們不寫程式碼或寫少量程式碼就能完成業務需求的交付,沒有程式碼就消除了前面提到的大多問題,這樣極大提高研發的交付效率及編碼幸福感。整個服務的編排效果如下圖所示:

 

我們可以通過線上拖拽的方式完成介面呼叫關係的編排,如介面的序列、並行和排他呼叫等,通過簡單的指令碼完成不同業務需求的定製,如對介面返回資料的裁剪、排序、格式化等操作。編排後可通過線上測試的功能,直接對編排的服務進行測試,實時秒級驗證功能的正確性,可以最大程度降低編碼及編譯打包的等待時間,提高業務整體的交付效率。

3.1 核心功能

視覺化服務編排系統的核心功能都是對BFF日常需求及研發流程的抽象,從介面的呼叫方式、出入參的處理、介面異常情況的處理、服務的除錯測試、服務的上線流程等幾個維度完成系統整體功能的設計。

  • 介面呼叫

介面間呼叫關係可以抽象為:序列呼叫、並行呼叫、排他呼叫。當依賴的介面間沒有依賴關係時,我們可以通過並行的方式,對所有所有同時發起請求,這樣可以減少服務的響應時間,從而提高系統整體的吞吐量。

當服務依賴的介面有依賴關係時,如介面A的入參需要通過呼叫介面B來獲取,那介面A和介面B之間就必須通過序列的方式呼叫,即需要先呼叫介面B,拿到介面B的響應結果才能才呼叫介面A。

排他呼叫就好比程式碼中的if...else,非A即B,這種場景主要用於根據條件判斷呼叫介面A還是呼叫介面B,或是執行其他的業務邏輯。

根據不同的業務需求和場景,序列、並行和排他的呼叫方式可能在一個服務中同時存在,所以功能的實現中必須支援不同調用方式的組合及巢狀。

 

  • 引數處理

介面的入參主要有靜態和動態兩種形式,針對靜態的入參,只需要在介面上提供輸入框配置即可。針對動態的引數,值可能來自於其他介面的返回結果,也可能來自動態生成的,如隨機數、UUID等,所以編排系統提供了通過表示式或指令碼的方式來取值或生成值,以適配靈活的業務場景。

 

  • 異常處理

介面的異常通常由兩個維度進行判定,一是介面是否呼叫成功,如果介面丟擲異常或超時都可以認為是介面呼叫失敗,另一種情況是介面返回資料是否符全預期,如果介面呼叫成功,但返回的資料不是預期的,如關鍵欄位沒有返回或返回的資料格式不正確,同樣需要將介面呼叫判定為失敗。

介面呼叫失敗的情況下,不同場景下的處理策略可能也會不一樣,因為有的介面並不是業務強依賴的,即便此接口出現問題也不會影響整個服務的響應。但有些介面則是服務強依賴的,如果請求失敗則要求返回兜底資料或直接返回錯誤。

所以對介面的異常判定和異常的處理方式設計了針對性的功能,即“ 異常斷言”、“異常處理策略”和“異常處理器”。

異常斷言需要使用者填寫表示式,用於判斷介面返回結果是否符合預期,當異常斷言返回True時,則認為介面的呼叫是失敗的。

異常處理策略則分為“忽略”和“中斷”,針對弱依賴介面可以使用“忽略”處理策略,此時如果介面呼叫被判定為失敗,則會執行對應的“異常處理器”,用於根據實際業務需求返回對應的兜底資料。針對強依賴的介面可以使用“中斷”處理策略,直接返回錯誤。

 

  • 除錯測試

將需求從之前硬編碼改為線上視覺化編排的方式來實現,原本的編碼習慣及除錯測試的相關功能就需要在線上得到體現,為了方便服務的除錯及測試,編排系統添加了除錯控制檯和介面資料Mock的功能。

除錯控制檯可以線上實時檢視服務執行輸出的日誌,方便研發同學對服務除錯過程中的問題進行排查和定位。

 

為方便研發同學根據用例自測服務,編排系統添加了介面響應Mock的功能,可根據入參進行匹配並返回特定的資料,這樣研發同學就可以不依賴業務方的介面返回,自己通過資料Mock的方式完成服務的自測,從而提高研發效率。介面Mock的功能如下圖所示:

 

  • 服務部署

基於傳統編碼的方式,當需求開發完成後,除去一些審批和驗證流程,上線過程可以概括為以下3個核心步驟:程式碼提交->編譯打包->上線部署,其中最關鍵的步驟為“上線部署”環節,我們需要重啟應用或容器,應用重啟需要的時間大多是分鐘級的,通常完成一臺機器的部署需要3-5分鐘,且隨著機器的增多,整個上線過程所需的時間也會增多。而通過編排實現的服務,整個上線過程都不需要重啟應用,其核心部署工作就是重新整理記憶體資料,只需要線上選擇要部署的機器,即可在秒級內完成服務的部署。

 

3.2 功能實現

視覺化服務編排系統的核心功能有兩個,一個是前端編排畫布,一個是後端服務執行引擎。編排畫布用於實現視覺化操作部分,其核心功能是定義可操作的功能並根據使用者的意圖生成後端可解析執行的DSL。

關於DSL的選擇,方向主要有兩個,一種是根據功能需求,定義一套全新的描述規範,另一種是基於已有的標準進行擴充套件。通過對前後端實現的複雜度及時間成本的考慮,最終決定基於BPMN規範進行裁剪和擴充套件,以實現編排整體的DSL規範定義。

BPMN(Business Process Modeling Notation),即業務流程建模符號,是一種流程建模的通用、標準語言,通常用來繪製業務流程圖,如OA審批流等。服務編排本質上也是流程編排,在BFF場景下,並不需要BPMN定義的所有功能,所以我們只需要對標準的BPMN進行裁剪即可。

  • 編排畫布

建模語言確定後,我們需要做的是確定如何實現編排畫布。通過調研開源BPMN建模工具,從易用性、開放性、活躍度等幾個方面考慮,最後決定基於bpmn.js二次開發來完成前端整個編排畫布的實現。bpmn.js是一個基於BPMN2.0渲染引擎和建模工具,基於Web,使用JavaScript編寫。

因為bpmn.js原生畫板及屬性面板是基於標準的BPMN的規範來實現的,在BFF場景下,其中很多配置和屬性是冗餘的,為了優化使用者的操作體驗及降低實現複雜度,我們對bpmn.js中的屬性面板基於VUE進行了重構,裁剪了BFF中不太關注的屬性,添加了BFF中特有的配置項,整個編排畫布效果如下:

 

  • 執行引擎

執行引擎是編排系統最核心的功能,其負責執行編排出來的服務。在執行引擎的研發過程中,調研了市面上已有的工具,但不管是從效能、靈活性還是可維護性上,都達不到我們的要求,另外基於已有的引擎做二次開發,時間成本及後續的維護成本也很高,所以最後決定通過自研的方式完成執行引擎的實現。

IO選擇

因為BFF的核心功能是介面呼叫及對介面返回的資料進行處理,所以網路IO這塊採用的是全鏈路非同步IO,基於事件回撥的方式實現,這樣做可以帶來兩個直接好處:

1. 高效能:IO非同步化後,使用極少的執行緒即可完成大量併發請求的處理,可明顯減少高併發場景下CPU上下文切換帶來的額外效能損耗;

2. 高穩定性:非同步IO消除了因上游介面響應延遲導致自身執行緒池打滿的情況,對服務穩定性有更好的保障;

預處理

相較於傳統執行引擎解釋執行的方式,自研引擎在初始化的過程中會將整個流程提前預處理為一個個“執行單元”,即“單元化”,不同執行單元進行巢狀組合完成整個流程的執行,這樣做的好處是,系統可以在執行前完成整個流程的預編譯,將一些沒必要在執行期的判斷、檢查邏輯提前到預處理環節,從而減少執行期的邏輯,提高引擎的整體執行效能。執行引擎核心功能參見下圖:

 

04執行成效

4.1 交付效率

BFF的業務需求由原本硬編碼的方式改為線上視覺化編排後,原來需要線下處理的流程全部轉為線上操作,規避掉了大多編譯構建及測試的等待時間,對人效提升明顯,有些需求從原來的小時級提升為分鐘級。

4.2 服務治理能力

通過編排實現業務需求後,可以由系統統一管理服務和介面,這樣介面和服務的元資料天然就是結構化的,介面和服務的引用依賴關係可以做到一目瞭然。由系統管理介面和服務後,可以新增更多維度的標籤,如介面歸屬的業務線、服務歸屬的頁面等,可為日常的管理提供更多維度的統計資料。

 

4.3 問題排查效率

基於服務編排實現的需求,天然具有流程圖屬性,如下圖所示,和編碼的方式相比,我們對服務的功能邏輯、介面前後依賴關係、呼叫關係都能一目瞭然,對我們日常的問題排查提供了有力幫助。

 

05總結

本文重點介紹了京東金融APP在BFF層實踐過程中遇到的問題,並引出視覺化服務編排在金融APP中的落地實踐,其中重點介紹了視覺化服務編排系統的核心功能及實現。視覺化服務編排系統已經穩定支援了金融APP從去年618到現在的所有發版迭代,對人效提升幫助明顯,希望能夠對大家在BFF的實踐有參考意義。