合約廣告平臺架構演進實踐

導讀 

從事 B 端業務系統研發多年,不免會有這樣的思考:B 端系統的技術挑戰是什麼?什麼樣的業務架構算好架構?本文結合百度合約廣告業務的發展歷程,介紹廣告投放平臺從單體架構到微服務架構演進過程中碰到的問題和思考。希望通過本文的介紹,讓大家更全面的理解 B 端系統的技術挑戰。

一、背景

1.1 合約廣告概念

合約廣告相比競價廣告,最大的特點是預先約定好廣告價格,即價格是預先確定的。基於這樣的特點,合約廣告的投放流程大致可以概括爲四個步驟:詢價 -> 下單 -> 投放 -> 結算。

  1. 詢價,銷售根據客戶的營銷目標選擇合適的營銷產品,並提交具體的投放定向和時長,系統結合銷售政策,自動計算產出各資源價格

  2. 下單,客戶按照 1 中的報價結果,確認需要購買的資源和具體的付款方式,完成下單後生成訂單,每個訂單的金額是確認的

  3. 投放,2 中的訂單完成審批後,系統按照事先約定的價格進行廣告投放,客戶在投中可通過系統進行投放和創意的管理,並可以實時獲取投放數據

  4. 結算,合約廣告按照投放模式分爲按時間計費和展現量計費,兩種計費方式的頻次都是天,最終實現在投放週期內逐步地扣除訂單全部金額。按天結算是對已產生投放部分的權益保障,畢竟合約廣告存在更改甚至退款的場景。

通常來說,合約廣告這種廣告採買方式更適合品牌展示類廣告,效果類廣告更多會採用實時競價。相比競價廣告,合約廣告在業務流程上更重投前。下面結合品牌廣告業務發展的三個階段,介紹下投放平臺的變化歷程。

1.2 業務發展

第一階段,品牌廣告業務高速發展期

2011 年,品牌專區產品開始平臺化售賣,並逐步建立品牌投放平臺:錦囊。在 2013-2018 6 年間,品牌業務高速發展,誕生了 Ax、Bx、Cx 等 10 + 條產品線,雖然錦囊平臺做爲投放的統一入口,但各產品線的投放能力仍舊是獨立建設,擁有各自的獨立投放平臺。在這種模式下,快速靈活地應對了市場的變化和需求,但同時也造成了投放平臺多,業務流程割裂的問題。

第二階段,尋求產品整合和流程統一

2019 年開始嘗試對合約類平臺進行整合,統一各產品售賣流程,包括產品線關停並轉、投放平臺融合、賬戶統一、資金池統一、標準化下單等項目。逐步落地合約廣告一站式平臺的建設 - 天啓平臺,真正實現合約廣告的標準化投放流程,提升規模化投放效率,支撐業務發展。在這個階段,各廣告的投放平臺入口逐步收斂,實現了操作入口的統一。

第三階段,滿足複雜營銷場景,整合營銷

隨着合約整合售賣(根據營銷場景選擇不同廣告產品的組合售賣方案,即同一個合同下可下單多類廣告,並享有對應的優惠政策)整體趨勢的加速增長,原本非標斷點式的支持方式已經無法滿足業務的增長,平臺化的解決方案是整合售賣規模化的必要條件。從 2021 年 Q3 起正式啓動,天啓平臺正式定位:統一的合約產品整合售賣平臺,滿足從簡單場景到複雜營銷場景的全投放鏈路服務能力。從技術視角看,旨在通過一個平臺(天啓),實現多資源廣告售賣場景下的統一,包括一個流程、一套賬戶、一套資金體系、一套投放表達。

1.3 架構演進

對應上述業務發展的三個階段,合約平臺的技術架構也經歷了多個版本的演進,濃縮後,可以概括爲 2 大類,2019 年前的單體架構和之後的微服務架構。

單體架構

2019 年前的單體架構(簡稱『1.0 架構』)圖如下所示,整體上分三層,1)統一入口層,提供用戶權限管理功能;2)各類廣告投放平臺獨立建設,服務獨立部署;3)抽象並沉澱基礎工具庫,避免各投放平臺的重複開發。

△1.0 煙囪式架構

品牌 1.0 架構本質是一個煙囪式架構,各產品線通過獨立平臺進行投放,開發、測試、上線互不影響,都能做到產品線維度的隔離,包括開發規範和迭代週期。這種架構配合當時品牌團隊的組織架構,在品牌產品野蠻式生長的初期起到了很重要的作用,成功孵化了一些創新產品。但是煙囪式架構一個很大的弊端就是『信息孤島』,隨着業務的發展,各投放平臺發散式迭代,逐步形成了一個一個的孤島。從技術視角看,各平臺大流程相似,但在實現細節上都不同,更嚴重的是,存在大量的重複性建設工作,從維護成本和人效上都有很大的優化空間。從業務視角看,各產品的打法也是各自爲陣,橫向缺少聯動,沒有形成 1+1>2 的局面,缺少整體視角的規劃。

微服務架構

業務方面,合約廣告場景化營銷和精細化服務的需求顯著;團隊方面,各合約類廣告平臺深度融合,孤島邊界逐步打破。原本煙囪式架構無論在業務複雜度的應對,還是服務穩定性及質量的保障,亦或是研發效能的提升,都已經遇到了瓶頸。基於軟件設計的最大目標:『設計符合業務的構造定律的演進方式,一種可以以最小的開發維護成本, 使業務更快更好的流動發展的方式』,19 年後,合約平臺架構逐步向微服務架構演進,以領域驅動設計爲準則,按照合約廣告的領域模型劃分微服務,構建了業務前臺、業務中臺、技術組件、基礎設施的四層業務架構。另外,基於消息機制解耦各服務,輔以組裝式業務流程的理念,拆解各種繁雜的業務流程,抽象並沉澱系統的 meta feature,靈活構造多種差異化的業務解決方案,提升系統的『可玩性』,從架構層面管理了系統風險和業務複雜度(百級別不同類型的售賣和投放場景)。

說到這,有些人會有疑問,對於品牌業務,微服務架構演進是否是必須的呢?是否存在過度設計?

當然,假如不考慮性能、健壯性、可移植性、可修改性、開發成本、時間約束等因素,用任何的架構、任何的方法,系統的功能總是可以實現的,項目總是能開發完成的,只是開發時間、以後的維護成本、功能擴展的容易程度不同。從後驗來看(包括系統可用性、擴展性、靈活性三方面),採用微服務架構的決策是正確的,或者說利遠大於弊。

在架構的演進過程中遇到了很多技術挑戰,後面的內容重點挑了幾個方面進行詳細闡述。

二、技術實現

2.1 服務架構

首先,整體看下合約廣告平臺的微服務架構,如下圖:

△合約廣告平臺微服務架構

總共分爲四層,業務前臺、業務中臺、技術組件(PAAS)、基礎設施(IAAS)。

  1. 業務前臺,總共分三個模塊,天啓平臺、運營平臺、業務前臺。

    • 天啓平臺:面向廣告主,提供合約廣告詢價、資源預訂、資源下單、投放設置、物料製作等核心能力,支持品專矩陣、展示矩陣、品牌全景 3 大類產品矩陣,多達 300 + 廣告資源的售賣。

    • 運營平臺:面向銷售和內部運營,幫助他們精細化運營廣告售賣各階段,目前售中的投放干預和運營管控能力建設相對完善,在開屏大促和品牌廣告日常運營工作中大幅提升操作的效率和安全性,讓原本一些『非標』操作通過平臺能力讓運營實現自助化。

    • 業務前臺:主要兩個作用,1)對天啓平臺和運營平臺的公共部分進行抽象並下沉,避免重複的業務邏輯和流程散佈在兩個模塊,減少開發和運維成本;2) 對各業務中臺的公共部分進行上抽,統一沉澱至此模塊,比如批量處理,讓各業務中臺的職責更加純粹,關注自己領域的建模。另外,針對跨多中臺的讀寫邏輯也統一在這一層實現,起到業務流程編排的作用。

  2. 業務中臺,按照合約廣告的業務流程和領域知識,劃分各業務服務,總共分爲 9 個業務中心和 2 個技術中心,每個業務中心都圍繞特定的業務領域展開,業務邊界非常明確。需要注意的是,9 大業務中心僅僅是從業務視角進行定義和劃分,並不代表每個中心就只有一個服務。基於技術架構和業務職責,每個業務中心可以繼續劃分爲多個模塊,例如投放中心又被劃分爲 檢索適配服務、物料審覈服務、實驗投放服務等。另外,服務之間嚴格劃定上下游關係(按照響應數據流向定義上下游概念),下游服務可以調用上游服務,上游服務嚴禁調用下游服務,上游服務的變更對下游服務產生影響必須通過領域事件(異步)的方式來實現,避免服務循環依賴(在服務治理章節中會展開介紹)。因此在整體系統中大量採用異步消息的方式,將業務實體的狀態變更視爲事件,驅動上游服務,雖然增加了測試階段的複雜度,但是有效保障了服務間關係的有序性。

  3. 技術組件,微服務架構後,各模塊的代碼庫也是獨立的,對於一些公共能力,如何能夠讓各服務低成本、無門檻的接入,從而達到統一各模塊業務解決方案的目標,減緩業務架構的腐化和熵增。鑑於此,通過 springboot starter 的方式構建了品牌團隊的業務中間件 brand-starters,成功收斂了 30 + 模塊的實現細節,在系統穩定性和架構健康度方面做出巨大貢獻,包括消息發送和消費、異步事件處理、異常報警、分佈式鎖、分級緩存、常用工具及輔助類等。

  4. 基礎設施,主要指部門級別的基礎設施和中臺,比如微服務解決方案 ,包括 RPC 框架、註冊中心、全鏈路追蹤、服務網關、虛擬化容器部署、FAAS。

2.2 模塊結構

上一節從整體視角介紹了合約廣告平臺的業務架構,這節從微觀視角介紹每個中臺的業務架構。各業務中臺採用多模塊的代碼結構,具體模塊劃分如下:

各模塊的依賴關係如下:

△模塊結構

值得注意的是:

  1. 各模塊間的依賴關係,demo-web、demo-task、demo-consumer 做爲頂層模塊,非常薄,這一層的主要作用是獨立發佈及部署,實現應用級別的隔離。頂層模塊調用 demo-app,app 模塊作爲服務的實現,存放了各個業務的實現類,主要分 command 和 query(CQRS 理念)。demo-app 可以調用 demo-domain,也可以調用基礎設施層 demo-infrastructure,domain 做爲領域層主要分 3 塊,model 領域實體,可以是充血模型(DDD 的概念);ability 領域能力,是領域對外暴露的服務能力;gateway 領域網關,主要是接口定義,這裏的接口可以粗略的理解成一種 SPI,也就是交給 infrastructure 層去實現的接口。

  2. demo-client 是服務對外透出的 API,API 的實現存放於 demo-app 模塊。出於運維考慮,或者讀寫分離的設計,可以方便的將需要獨立部署的 API 從 app 模塊上抽至頂層,做爲獨立模塊進行流水線發佈和部署。實現服務的隔離部署,同時又能獲得共享同一個代碼庫的好處

  3. 前面提到的 domain 和 infrastructure 層的依賴倒置,是一個非常有用的設計,進一步解耦了取數邏輯的實現。domain 層依賴接口,不感知具體實現,例如 CustomerGateway 裏定義了接口 getByById,要求 infrastructure 的實現類必須定義如何通過消費者 Id 獲取消費者實體信息,而 infrastructure 層可以實現任何數據源邏輯,比如,從 MySQL 獲取,從 Redis 獲取,還是從外部 API 獲取等等。

  4. 領域與功能的分包策略,每個模塊的分包策略都遵循準則:先按照領域分包,再按照功能分包,這樣做的其中一點好處是能將腐爛控制在該業務域內。比如消費者 customer 和訂單 order 兩個領域,在 domain 模塊下先分成 customer 和 order 兩個包,然後再按照 model、ability、gateway 進行功能劃分。假設 customer 和 order 是兩個後端開發並行開發,兩個人對於 dto,util 這些文件夾的命名習慣都不同,那麼只會腐爛在各自的業務包下面,而不會將 dto,util,config 等文件夾放在一起,極容易引發文件衝突。

通過上面的應用架構劃分,統一了各業務中臺的分模塊和分包策略,成功降低了各模塊的學習和上手成本,較好控制了業務架構和模塊代碼的腐化程度。同時通過頂層模塊的劃分,靈活實現了同一代碼庫多應用部署的能力,從物理層面隔離 web 服務、定時任務、消息消費、rpc 服務,使服務具備靈活按需擴展的能力,進一步提升服務的穩定性。

2.3 服務治理

微服務架構後,服務之間的交互通過網絡進行而非單體時代的內存方式,所以整體來說系統會變得更加脆弱,服務治理就是爲了解決此類問題。常規的服務治理有四板斧:第一,一定要設置服務調用的超時時間;第二,要考慮重試的邏輯;第三,考慮熔斷的邏輯,不要被下游拖死;第四,一定要有限流的邏輯,不要被上游打死。即超時、重試、熔斷和限流。沒錯,這四板斧的確是服務治理中的常規手段,但在我看來,服務治理並不侷限於此。我們以終爲始,看看服務治理的終極目標是什麼?我認爲主要 3 個方面:服務可用性、系統可觀測、架構防腐化。

可用性

服務可用性的建設包括系統性能優化、服務自愈和自檢能力建設。

服務性能

1. 微服務框架升級

服務 RPC 框架整體遷移至部門最新的雲原生解決方案 gravity+starlight,取代了原先的 zookeeper+stargate。在服務性能和治理方面有了大幅提升:

遷移過程中,gravity 與 zk 雙向同步服務註冊信息,實現業務的平滑無感遷移。

2. 系統性能深度優化

對合約廣告系統進行了全面的性能盤點和優化,性能整體提升 2 倍,總結爲如下 7 個優化點:

服務自愈和自檢

爲了更好的保障系統的可用性,服務需要具備自愈和自檢能力。服務自愈能力主要通過冪等處理 + 事件持久化 + 邏輯重試來實現,通過自愈能力的建設,可以大幅降低微服務架構升級後帶來的 IO 通信不穩定問題,同時讓系統對性能和穩定性較差的外部服務有更好的容忍性,有效提升系統的整體可用性。系統的自愈能力主要解決的是『偶發性』技術問題,比如網絡抖動導致的遠程調用失敗、事務併發導致的樂觀鎖衝突等,對於代碼 bug、業務邏輯錯誤、數據不一致等問題無能爲力。所以除了自愈能力,服務還需要具備自檢能力,能夠將錯誤自動檢測出來,並及時通知到對應人員進行處理。

服務的冪等處理這裏簡單提一下,不做過多展開,主要有幾種方案:

  1. 數據庫唯一鍵,通過數據庫的約束實現新增和刪除操作的冪等。

  2. 數據庫樂觀鎖,通過增加額外字段(版本號)實現更新操作的冪等。

  3. 防重 token 令牌,調用方在調用接口的時候先向後端請求一個全局 ID 做爲 token,後續請求的時候都帶有此 token(建議放到 Headers 中),可以解決客戶端連續點擊或者調用方超時重試等情況,適用於新增、更新和刪除操作

  4. 下游傳遞唯一序列號,與 3 不同的是,這個唯一序列號由調用方生成,生成方式可以是無業務含義的全局 ID,也可以是帶有業務含義的 ID,比如訂單行 ID。服務方通過此 ID 記錄進行存在和不存在的操作(結合 redis 實現操作的記錄),適用於新增、更新和刪除操作

自愈能力 - eventlog 基礎組件

利用 springboot-starter 機制沉澱 eventlog 基礎組件,讓業務方低成本接入,使服務具備自愈能力。組件整體架構圖如下:

△eventlog 基礎組件

步驟 1 是同步持久化事件,由業務方引入組件後調用現成方法實現;步驟 2 是異步消費處理事件,整體處理流程採用模板模式 + 策略模式,通過模板模式實現處理流程的業務編排,對事件處理前、中、後都設置擴展點,兼顧業務模塊的接入成本和擴展靈活度。事件處理採用策略模式,將事件類型做爲策略路由,實現各類事件處理的互相隔離和高擴展性。另外通過可視化配置(amis 配置,即愛速搭,低代碼前端頁面搭建平臺),統一監控事件日誌表,對超時處理的事件進行報警、清理等操作。

事件日誌實體模型採用 event_type + biz_code 的二級模型,event_type 唯一標識了一類事件,是事件處理時的策略路由 key,biz_code 由業務方自定義,用來唯一標識某類實體。attach 是擴展字段,供業務方自定義,attach 不宜過大,如果過大,建議通過 biz_code 後反查業務數據。

自檢能力 - 核檢中心

服務的自檢能力主要通過核檢中心來實現,核檢中心功能上分兩部分,核檢任務 + 消息中心。核檢任務按業務場景對數據進行覈對校驗,解決微服務架構後分布式事務造成的數據不一致,同時,端到端的核檢也可以做爲在線監控,第一時間感知系統 bug;然後通過消息中心將異常通知到對應人員。同時,面對大量的報警信息(系統錯誤、數據一致性、業務正確性等),消息中心做爲統一的管理端,提供了按場景分組報警、歷史報警信息查詢、報警優先級設定、誤報熱屏蔽、報警羣進組熱修改等功能,提升監控的有效性和處理效率。

核檢中心整體模塊圖如下:

△核檢中心模塊圖

可觀測

系統的可觀測程度也是服務治理的一個非常重要目標。提到服務的可觀測性,大家容易想到的一般都是:微服務調用關係(拓撲圖呈現)、接口性能(各種分位值指標,性能優化利器)、系統異常(各種監控配置)、資源利用率、日誌鏈路追蹤(線上排查必不可少)等,這部分主要依託於部門的微服務解決方案 Jarvis 平臺實現,所以在這裏不做過多介紹,這裏主要想介紹的服務可觀測主要是指上層業務應用。

企業級微服務解決方案 Jarvis 是商業平臺部基礎技術團隊研發的面向複雜業務系統的應用託管平臺,爲商業應用提供高可用和分佈式的微服務架構解決方案。Jarvis 提供了一系列強大的功能,充分利用百度資源虛擬化能力,提供分佈式服務框架、服務治理、統一配置管理、分佈式鏈路跟蹤、容量規劃、高可用及數據化運營等功能。

前面其實已經提到過,合約廣告的整體業務鏈路比較長,經歷了售前詢價 -> 下單 -> 合同審批 -> 物料製作 -> 投放 -> 計費,每個環節都可能成爲廣告投放的卡點,如果出現問題,比如流程阻塞,如何能夠快速定位問題,甚至提前感知問題,做到整個流程的透明化、可觀測呢?

整體思路是以業務實體爲中心,記錄實體全生命週期的變化,當某個階段(實體狀態)停留時間超出預期,就有可能存在潛在的異常,通過服務看板和消息中心,及時通知對應的運營進行處理跟進。通過追蹤業務實體的生命週期,實現系統業務流程的可觀測性,爲後續流程優化、業務提效提供數據分析基礎。

業務實體生命週期的追蹤實現方案主要如下圖:

△業務實體生命週期追蹤

總結來說就是三種方案:

  1. 通過訂閱 mysql binlong,監控業務實體的核心狀態字段(對應部門已有解決方案 WATT),一旦字段變更就會觸發增量消息,服務端消費後持久化,再以服務看板的形式對外呈現。這種方式的優勢是對業務模塊無侵入,劣勢是依賴業務模塊的數據庫設計,另外有些實體的生命週期並不一定體現在數據表的字段變更,無法通過訂閱 binglog 的方式感知

  2. 通過日誌打印 -> 採集 -> 解析的方式實現實體全生命週期的追蹤。這個方式的優勢是百度已有一整套現成的解決方案,可以直接複用;劣勢是需要侵入業務代碼,按照規範打印日誌,同時日誌採集和解析的配置門檻較高,調試較困難,不容易上手

  3. 提供用於追蹤實體生命週期的埋點 sdk,在需要監控的地方埋點。這個方式的優勢是靈活度非常高,可以實現任何追蹤需求;劣勢是侵入業務代碼,需要業務模塊顯式進行調用

最終我們採用了 1 和 3,業務實體的追蹤主要通過方案 3 來實現埋點,一些額外輔助信息通過 方案 1 進行同步。

防腐化

很多科學家提到的熵增定律非常好的揭示了自然現象的本質:任何孤立系統,在沒有外力作用的情況下,其總混亂度(熵)會不斷增大。當然軟件系統也是如此,隨着軟件系統的功能不斷增加,系統的混亂度也在不斷增大。爲了降低軟件系統混亂的速度,必須要對其施以外力。那麼這裏的『外力』可以從哪些角度入手呢?

  1. 分析每個應用的修改頻次,哪些應用頻繁修改,哪些應用相對穩定。對於頻繁修改的應用,是否引起修改的業務需求是相同的。那麼這些大概率綁定在一起修改的服務被拆分在不同的應用,是否是不合理的,值得進一步商榷。如果一個應用,無論什麼需求都需要升級,那麼這個應用是否已經足夠小,是否需要進一步拆分,剝離變與不變,將不變的部分進行抽離和沉澱?

  2. 定期觀察每個服務的調用情況,包括次數、性能和拓撲。是否存在一些冗餘服務可以清理?是否存在一些服務性能呈現惡化趨勢,需要及時介入優化?是否存在某些業務流程中存在重複調用的情況?如果有,需要制定計劃進行治理,否則就會成立歷史債務,讓業務架構逐步腐化。

  3. 需要定期去掃描檢查應用代碼,包括重複邏輯是否散佈於多個應用、是否存在不規範的代碼邏輯(每個團隊根據實踐總結沉澱,比如 枚舉類的使用、IO 循環調用等)、是否存在冗餘代碼需要清理、模塊結構和分包策略是否符合規範

  4. 定期的 CR 各應用代碼,是否存在跨領域的邏輯,比如報價中心處理了訂單中心的邏輯(非報價域的邏輯),導致微服務的劃分邊界模糊

防腐化這塊工作其實很重要,目前也還處於初級的摸索階段,需要進一步結合業務實際,沉澱最佳實踐。這裏先以微服務循環依賴治理爲例,做個簡單介紹。

當微服務中的循環依賴形成閉環後會造成 2 類主要危害:

  1. 服務間強耦合導致各服務很難獨立部署,違反了微服務『自治與隔離』的設計初衷,最終微服務架構會逐步演變爲『分佈式大單體』,失去了微服務架構演進的意義。

  2. 循環依賴可能會導致一些循環調用或併發問題,造成一些複雜難以定位的問題,下面以用戶中心和訂單中心爲例來說明

△循環依賴導致的併發問題

上述圖中有兩個服務,訂單和用戶中心,藍色箭頭表示訂單中心對外提供的服務 ,實現訂單狀態更新,其中會調用用戶服務更新客戶狀態,標記此客戶已有下單記錄。紅色箭頭表示用戶中心調用訂單中心,用戶服務在標記完客戶狀態後反過來會調用訂單服務,持久化訂單上客戶信息。上述調用形成了閉環,最終會引起訂單數據庫中的版本衝突,導致更新失敗。那麼如何避免這種循環依賴呢?總結以下幾個準則:

  1. 明確服務邊界和定位,劃分上下游服務,下游服務可以調用上游服務,但是上游服務不能依賴下游,如果要進行通信,採用領域事件的方式,比如消息通知。

  2. 數據不要過多冗餘,儘量通過數據 id(能夠唯一代表數據且不變的屬性)來進行關聯,即只存引用。

  3. 如果存在必須要通過上游服務同步調用下游服務才能完成的功能,得反思是否上游服務缺少了相應的業務域。如果不是,可以借業務前臺來實現各服務的調用編排,或者肯能存在微服務拆分不合理,這種場景需要重新規劃,拆分出一個更上游的服務供調用。

回到剛纔的實際例子,治理方案是採用領域事件的改造方式,訂單服務是下游服務,用戶服務是上游服務,用戶服務更新訂單客戶信息從同步調用方式改爲消息通知,不感知具體的訂閱方,實現解耦。

**2.4 **服務迭代

微服務架構改造後,原來單體架構的迭代方式已經不再適用,我們看一個實際例子:

從上述例子中可以看到,微服務架構後,一個業務需求會涉及多個模塊,複雜度不盡相同,如果中臺服務的每個升級無法做到向前兼容,那麼勢必會導致需求間的耦合,一旦並行開發的分支增多,因模塊間的耦合導致的整體回滾概率將會指數級增長。仍舊是上述這個例子,如果需求 1 中的中臺 B 有 BUG,需要回滾,那麼是否導致需求 2 中的所有模塊都要回滾,包括中臺 D,即使它的改動點非常小。

總結以下,造成上述局面的 2 個主要原因:

  1. 迭代升級的視角只有需求維度,中臺服務被割裂,缺少另一個以中臺爲主的視角

  2. 自動化測試能力不足,過度依賴黑盒測試會導致風險後置

針對這兩個問題,我們的解法主要有 3 個方向:

  1. 規範需求迭代流程,強化以中臺爲軸的虛擬團隊。

  2. 從需求評審、技術詳設、開發、聯調、測試到上線,制定詳細的全流程規範,保障團隊有序運轉。同時,強調各中臺的自治,迭代升級必須做到向前兼容,依賴模塊的回滾不影響自身的上線計劃,反覆強調容錯、兼容、演進式的設計理念。

  3. 加強自動化測試能力,達到自動準出標準。自動化測試能力包括各模塊的單測和集成測試。模塊單測通過插件集成至流水線,對於沒有達到覆蓋率的代碼禁止合入,特殊情況下,可以說明理由,讓模塊負責人豁免。集成測試從業務前臺出發,按照業務場景優先級逐步建設,觸發方式分爲每日例行任務和迴歸測試時的手動觸發。

  4. 提供服務 mock 能力,在合適的場景下可以解耦對其他服務的依賴。落地聯調中心,實現服務級別的動態 mock 能力,並通過 starter 方式讓業務模塊低成本接入。整體設計分爲兩部分,client 端和 server 端,如下圖:

△mock 中心

其中,服務端的可視化 mock 規則配置支持動態規則,對於一些無法用動態規則描述的需求也可以通過低成本的代碼開發實現定製化邏輯。

最終期望能夠讓每個中臺服務達到『自治與隔離』,從而解耦各需求點的上線,如下圖:

可以看到,上線粒度從需求維度細化到了中臺 fetaure,使整體交付風險指數級下降。當然,對於微服務架構系統,如何做到高效聯調和測試仍是一個正在不斷探索的方向。

三、總結

本文主要介紹了合約廣告微服務架構演進中的一些最佳實踐,做一個簡單的總結。

  1. 服務拆分:從實際業務出發,基於領域驅動模型的理念,建立合適的業務模型。這部分一定要深入業務細節,理解業務運轉原理,抽象出業務本質。通過合理服務拆分,可以更高效地解決複雜業務問題,如果將 7 個業務中臺類比爲正交的座標軸,那麼原來低維的複雜問題(單體架構)投射到高維後(微服務架構),大概率會變得沒那麼複雜;另外,對於本質業務複雜度問題,通過服務拆分,可以很好的將複雜性隔離至對應領域服務,更好地管理複雜度,防止外溢。

  2. 模塊結構:借鑑 COLA 架構,結合實際情況,制定規範,其中包含了多種設計理念:DDD、事件驅動模式、CQRS 模式、依賴倒置。相比服務拆分,模塊結構是從微觀視角制定各微服務的代碼組織,減緩腐化速度。

  3. 服務治理:總結了系統性能、業務可觀測性和防腐化三個方面的一些心得和最佳實踐,在我看來,一個好的業務架構,能夠很好的管控業務複雜度,甄別業務中的『變』和『不變』。所以,定期梳理分析各服務的升級頻率、調用關係等是非常重要的。

  4. 服務迭代:服務及架構的迭代需要平滑有序,做到容錯、兼容、演進式,避免大量應用改造。同時各微服務要做到自治與隔離,降低相互之間的耦合,做到在架構演進過程中每個服務都能順利地『死去』與『重生』,就像生物進化一樣。(本文多次提到的領域事件方式是降低服務耦合的有效手段)

所以回到本文開頭的 2 個問題,B 端系統最大的技術挑戰我認爲是業務複雜度的治理,通過合適的技術選型在賦能業務的同時又能很好地管控技術和業務複雜度。我心目中好的業務架構標準就是提升效率,這裏的效率包括交付效率、運維效率以及演進效率。

最後想說:沒有完美的業務架構,貼合業務實際的就是好架構,一個好的業務架構一定是結合業務實際演進而來的。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/PJ07Z3jJBevWqDZQf448uA