平臺化建設思路淺談

木小豐發表於2022-02-17

隨著業務的不斷髮展,軟體系統不可避免的走向熵增:複雜度越來越高、研發效率越來越差、穩定性逐漸降低等。這時抽象核心能力,走向平臺化的道路成為很多系統的首要選擇。筆者結合自己的經驗,總結了平臺化建設的幾種思路,希望對大家建設平臺化有所幫助。

平臺化有以下優點

  • 複用性強:複用核心邏輯,業務功能只在平臺之上的業務層建設,降低建設成本;
  • 研發效率高:平臺服務作為通用能力基建,業務只需要關注需求,不用關心平臺底層複雜能力實現;
  • 降低複雜性:平臺都有合理的職責邊界和模組劃分,對外開發的介面也都直觀簡潔;
  • 穩定性:平臺服務的穩定性是重中之重,一般有專門的團隊維護,穩定性比一般的業務系統強;

平臺化建設幾種方式

1、嵌入式

平臺提供類似容器的功能,業務方以Jar包形式嵌入到平臺當中,類似於傳統的多個war包部署在tomcat中。這種實現方式平臺提供通用能力介面和業務擴充套件點,業務方實現業務擴充套件點來實現業務邏輯。一般有統一的入口(比如tomcat提供的域名+埠),根據租戶標識來區分業務方(比如tomcat的serverPath),平臺底層的儲存及模型中也都有租戶ID標識。

image

優勢:

  • 運維: 平臺統一運維,業務方工作量降低;
  • 對外介面:對外統一介面,呼叫者的工作量會降低;

劣勢:

  • 業務方功能受限:一般不能做重量級任務,平臺以擴充套件點方式提供給業務方擴充套件,除此之外的能力都應該被限制;
  • jar包衝突、類衝突問題:平臺本身包含了很多依賴,業務方jar包也會有很多依賴,如果有衝突會導致整個平臺不可用,下文會介紹幾種規避方法;
  • 業務隔離性差:不同業務方之間可能相互影響;

處理業務隔離的常用方案:

  1. 每個業務方提供一個叢集;
  2. 使用類載入器隔離jar包,但可能依然解決不了jar包衝突的問題;
  3. 業務方提供fatjar,更改所有依賴包的package路徑,比如MavenShadePlugin外掛;

2、介面依賴式

平臺也可以通過遠端依賴的形式來整合業務的功能。這樣能避免jar包衝突、業務功能受限等問題。此方案也會有一些限制,比如原jar包依賴的方式都是本地呼叫,現在都是遠端呼叫,對效能、事務保證等都提出了新的挑戰;需要保證介面的相容性;平臺與業務的互動由原來物件互動變成RPC介面,設計到編解碼等;

這種方案適合平臺與業務層互動較少、擴充套件點比較固定的場景,比如API渲染服務,平臺提供渲染模板介面,業務方實現介面填充欄位。

image

優勢:

  • 隔離性:平臺和業務完全隔離;
  • 業務方方便整合其他業務:平臺擴充套件點只是作為業務方的一種能力,可以在已有的服務上提供;

劣勢:

  • 介面變更復雜:如果要變更介面,所有業務方都需要迭代;
  • 互動複雜:都是通過RPC互動,一些擴充套件欄位需要編解碼成String傳輸;
  • 平臺方兜底:如果業務方服務異常,平臺方需要提供限流、降級、兜底的能力;

3、中臺式

上面講到兩種模式都是以平臺為主,對上層來說都是感知的平臺,適合互動介面比較固定的場景,對互動差異性大的業務不是很適合。中臺式的思路是提供業務通用能力,業務方基於中臺能力快速開發自己的業務,並獨立提供服務或頁面。

image

中臺和平臺的區別:

  • 視角不同:平臺關注的是去重、整合;中臺關注的是複用;
  • 價值體現:平臺直接對外提供服務,是一個功能大集合;中臺是其他產品的一部分,為了其他產品更好的提供服務;

優勢:

  • 能力聚焦:只需要提供核心能力支撐,不關心和使用者互動;
  • 複用性更強:平臺不依賴業務的擴充套件點,而只是業務方到平臺的單向依賴;

劣勢:

  • 個性化能力弱:因為沒有擴充套件點,只提供通用能力;

平臺化建設常用模式

1、DSL領域特性語言

DSL(Domain Specific Language)是針對某一領域,具有受限表達性的一種計算機程式設計語言。 DSL 具備強大的表現力,常用於聚焦指定的領域或問題。

在平臺化建設中,DSL一般用來遮蔽平臺複雜的業務邏輯,以DSL的形式對業務方暴露簡潔能力介面。

比如非常有名的Gradle,就是一種DSL表達,具有比Maven更靈活的特性,關於如何構建DSL,請參考作者部落格:使用Groovy構建DSL

2、Specification規約模式

Specification 模式用於解決「業務規則」相關的複雜性。

什麼是業務規則呢?比如電商業務場景中需要判斷:賬戶有效狀態、是否是VIP、活動價有效期、賬戶餘額等。在常規的程式碼開發中,有三種處理方式:

  • 在業務流程程式碼中case by case的編寫;缺點是會導致能力複用性、可維護性越來越差;
  • 新建靜態類,比如OrderValidator、TimeValidator等,缺點是處理組合邏輯(and、or)力不從心;
  • 在模型類中校驗,缺點是類中會摻雜越來越多的非領域邏輯,這種邏輯太多會掩蓋業務核心的業務規則;

Specification模式認為校驗邏輯都是“動作”,需要單獨建模,且模型都是值物件,介面通用模式如下:

public interface Specification<T> {
boolean isMatch(T domainObject);
}

通過實現 Specification 介面,我們可以對不同的領域物件擴充套件不同的校驗邏輯,而這些類都是可以複用的。

同時這些 Specification 可以作為基礎元素進行任意的組合,組合更為複雜的校驗規則與篩選邏輯。

當然Specification 不僅僅適用於過濾資料,它的核心是組裝業務規則。例如 Spring Data JPA 提供了基於 JPA 的 Specification 模式的查詢功能,使用起來非常方便,以下是一個示例:

public List<Student> getStudent(String studentNumber, String name) {
Specification<Student> specification = new Specification<Student>(){
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//用於暫時存放查詢條件的集合
List<Predicate> predicatesList = new ArrayList<>();
//equal
if (!StringUtils.isEmpty(name)){
Predicate namePredicate = cb.equal(root.get("name"), name);
predicatesList.add(namePredicate);
}
//like
if (!StringUtils.isEmpty(nickName)){
Predicate nickNamePredicate = cb.like(root.get("nickName"), '%'+nickName+'%');
predicatesList.add(nickNamePredicate);
}
//最終將查詢條件拼好然後return
Predicate[] predicates = new Predicate[predicatesList.size()];
return cb.and(predicatesList.toArray(predicates));
}
};
return repository.findAll(specification);
}

3、異構

平臺提供的通用能力如果不能直接滿足業務的需求,需要提供擴充套件能力以適配業務模型來達到異構的目的。支援業務擴充套件模型一般有以下幾種方式:

  • String ext
  • Map<String,String> ext
  • Class:一般用於嵌入jar式

還有另外一個問題需要解決,平臺作為通用能力,有平臺自身的模型,如何將平臺模型轉換為業務模型?簡單的做法是作為擴充套件點開放給業務方實現,不過作為業務方,應該關注的是業務模型,平臺模型有自己的規則且平臺為了通用化,模型都會非常複雜。

一個更完善的平臺應該支援更靈活的異構模型支援,常用是方案是欄位配置化:

  1. 在平臺申請一個模型的定義,一般包括型別,長度,限制規則等(比如必須是正整數);
  2. 業務方配置欄位和平臺模型的對映關係,如果需要動態能力,可提供Groovy或Aviator等指令碼支援;
  3. 轉換為業務方模型:根據使用者配置,自動轉換並給使用者返回業務模型;
  4. 轉化為平臺模型:引數中需要傳入後設資料類名,平臺按照配置規則進行有效性校驗;如果需要自動轉化,則需要在配置服務支援雙向對映

4、統一儲存

平臺除了平臺通用模型的儲存支援,還需要支援不能轉換為平臺模型業務模型儲存。有以下幾種方案:

  1. 寬表:採用列式儲存引擎,可方便的建立、修改列,缺點是常用的列式儲存引擎一般不能提供的很好的事務支援;
  2. 列轉行:資料表只有三列:id、key、value,查詢及儲存時在repository層進行轉換,缺點是不能join、不支援修改列;適用於不太複雜的業務場景;
  3. 後設資料:完全接管資料庫操作,根據不同欄位格式自動儲存到不同列,完善的後設資料平臺還支援分庫分表、擴縮容、資料遷移等能力,建設成本最高;

總結

平臺化建設是一個非常複雜的工程,涉及的業務方、方案選擇比較多,難點和投入成本也都差異較大,沒有一套完美的方案能覆蓋所有業務場景,本文提供了幾種參考方案和設計模式,具體的方案還需要讀者結合自己的業務場景來挑選最適合自己的方案。

作者簡介:木小豐,美團Java技術專家,專注分享軟體研發實踐、架構思考。歡迎關注公共號:Java研發
本文連結:平臺化建設思路淺談

相關文章