閱讀原文:【技術分享】微服務開發(fā)的幸福感,是如何提升的?
點擊關注“八戒技術團隊”,閱讀更多技術干貨
隨著微服務的流行,越來越多公司使用了微服務架構,但由于公司業(yè)務的特殊性、技術棧的歷史原因等,都需要選擇一個適合自己公司的服務開發(fā)框架,對框架進行規(guī)范定義,集成自研組件和系統(tǒng),讓業(yè)務迭代實現(xiàn)更快速,讓開發(fā)人員使用更便捷。
本文將基于SpringBoot,從框架約束、自研中間件集成、強類型客戶端、接口文檔等多個方面介紹服務框架的設計與實踐。
一、背景介紹
公司后端服務是以Java生態(tài)為主,有基于Dubbo的RPC服務、基于SpringBoot的HTTP服務兩種開發(fā)模式,所有服務基于K8S的容器云雙機房獨立部署,支持雙活流量的架構。
結合公司上下文環(huán)境、業(yè)務規(guī)模,綜合考慮技術棧統(tǒng)一、服務治理、使用成本等多方面的因素,經(jīng)過多部 商議,確定將“基于SpringBoot開發(fā)HTTP服務”作為主要開發(fā)模式。公司每天都有一些新的微服務產(chǎn)生,很多自研組件服務和中間件系統(tǒng),需要服務開發(fā)者單獨接入,為了規(guī)范和簡化后端服務開發(fā)者集成應用,一套規(guī)范、集成的開發(fā)框架就變得非常有必要。
二、基于SpringBoot的服務框架設計
1、如何統(tǒng)一規(guī)范框架的使用?
統(tǒng)一規(guī)范可以通過默認約定、強制校驗、自動內(nèi)嵌等多種方式來實現(xiàn),下面將分別舉例說明。
統(tǒng)一管理依賴包(默認約定)
基于Maven的依賴包管理,通過Partent統(tǒng)一定義依賴包及版本,默認引入必須的依賴包和插件。創(chuàng)建工程自動生成代碼時,默認約定繼承Parent,開發(fā)者只需引入必要的Starter即可,開發(fā)者可以修改繼承關系,但不推薦。
依賴包的統(tǒng)一管理,可以避免不同版本包沖突的麻煩,也方便后期公司統(tǒng)一升級依賴包和版本。
統(tǒng)一參數(shù)格式(強制校驗)
返回參數(shù)都繼承BaseResponse,請求參數(shù)都繼承BaseRequest。強制校驗接口服務來保證參數(shù)規(guī)范性,在工程啟動時自動檢測,不遵循規(guī)范的工程將無法正常啟動,繞過校驗的工程不納入公司后端體系,很多核心能力均無法正常使用。
統(tǒng)一參數(shù)格式,不僅可以同時支持HTTP調(diào)用、強類型客戶端,同時規(guī)避了HTTP接口的濫用,簡化規(guī)范了錯誤處理。
統(tǒng)一處理異常(自動內(nèi)嵌)
通過Spring的RestControllerAdvice可以對全局異常統(tǒng)一捕獲,并對異常統(tǒng)一處理。異常處理自動內(nèi)嵌到核心包中,只要使用該框架,就自動生效。
統(tǒng)一異常處理,不僅規(guī)范了異常返回格式,兼容了強類型客戶端,日志統(tǒng)一記錄,并對返回的異常信息進行脫敏處理。
2、如何簡化自研中間件組件和系統(tǒng)的集成?
所有中間件依賴包都在Parent中統(tǒng)一管理,對于自研的通用類組件(比如日志組件、線程池組件、web安全組件、自研的工具類組件等),默認在Parent中已引入,開發(fā)者可以直接使用。
公司有很多自研的中間件組件或系統(tǒng),或者根據(jù)公司環(huán)境二次開發(fā)過的開源組件,只能按照公司的特定的方式進行接入使用,有一定的接入成本。為了接入更方便,都做成了可插拔的組件,通過Starter方式進行接入。
使用Starter方式,簡化了依賴、簡化了配置、簡化了接入代碼。
作為后端服務,核心能力是對外提供服務,或者調(diào)用其他服務。如果使用REST方式訪問遠程HTTP接口,難以將接口管理起來,當接口變動的時候可能需要修改多處。
在技術調(diào)研過程中,我們發(fā)現(xiàn)SpringCloud提供了OpenFeign來解決這個問題。
3、如何實現(xiàn)強類型的HTTP客戶端?
OpenFeign是一種聲明式、模板化的HTTP客戶端,在Spring Cloud中使用OpenFeign,只需要定義接口和注解,可以做到使用HTTP請求訪問遠程服務,就像調(diào)用本地方法一樣。
但OpenFeign和我們公司技術環(huán)境不一致,加上太多歷史項目也無法支持OpenFeign,于是我們借鑒OpenFeign思想,基于開源Fegin開發(fā)了適合公司環(huán)境的ZbjFeign,支持在SpringBoot和普通Spring環(huán)境中使用。
雖然實現(xiàn)了聲明式調(diào)用,如果每次都要寫接口定義和注解,還是很不方便。為了解決這個問題,我們開發(fā)了一鍵發(fā)布Client包功能,通過掃描Controller接口方法元數(shù)據(jù),基于ZbjFeign生成接口調(diào)用Client,構建打包發(fā)布到公司Maven倉庫。后端開發(fā)者只需引入一個包,就可以像調(diào)用本地接口一樣調(diào)用遠程HTTP接口。對于前端NodeJS調(diào)用,也生成了對應的生成物,支持前端框架的“強類型”調(diào)用。如果開發(fā)者要看接口文檔,我們也提供全公司統(tǒng)一、完整的接口文檔。
4、如何實現(xiàn)文檔的統(tǒng)一管理?
公司所有文檔都是基于Confluence進行管理的,接口文檔也不例外,于是我們也實現(xiàn)了在發(fā)布階段,一鍵發(fā)布接口文檔。后臺實現(xiàn)也是自動掃描Controller接口元數(shù)據(jù),通過模版生成HTML片段,并提交到Confluence。接口文檔中提供了Java強類型客戶端調(diào)用、HTTP調(diào)用兩種方式的參考。
Client和文檔都有了,接下來我們通過案例看一下如何使用。
三、框架使用案例
1、Starter的使用案例
通過Starter方式使用分布式消息隊列 RabbitMq,只需要引入Starter,就可以直接使用了。
第一步:引入依賴Starter。
第二步:消費者監(jiān)聽隊列消息。無需做任何配置,具體代碼如下。
說明:公司的RabbitMQ是經(jīng)過二次開發(fā)的,不是通過“地址+賬號”訪問,而是通過申請的業(yè)務ID進行訪問。
2、強類型客戶端使用案例
只需要引入Client包,無需做任何配置,就可以像調(diào)本地方法一樣調(diào)HTTP服務。
第一步:引入Client依賴。
第二步:直接通過強類型進行HTTP接口調(diào)用,就像本地方法一樣。
說明:客戶端包生產(chǎn)時內(nèi)置了遠端服務的域名,如果發(fā)生變化可以從自研的配置中心修改。
四、未來框架的思考和展望
最后,給大家分享一下關于未來工作,我們的一些思考與規(guī)劃,還不太成熟,拋出來和大家探討一下。
1、服務治理本文未涉及到服務治理相關部分(熔斷、限流等),是因為考慮到解耦、靈活性等多方面因素,我們并沒打算像Dubbo或者SpringCloud, 通過代碼庫方式耦合在應用程序生命周期中,而是從應用生命周期脫 離出來,下沉到基礎設施或者網(wǎng)絡層,進行統(tǒng)一治理。
2、應用可觀測性微服務架構中,故障可能出現(xiàn)在任何地方,做可觀測系統(tǒng)已經(jīng)在我們 計劃中,通過日志、鏈路跟蹤、度量等手段,讓各數(shù)據(jù)之間產(chǎn)生更多的關聯(lián),使每一次 App 點擊所產(chǎn)生的多次服務調(diào)用耗時、返回值和參數(shù)都清晰可 ,甚至可以下鉆到第三方軟件調(diào)用、SQL請求、節(jié)點拓撲、網(wǎng)絡響應等信息中。運維、開發(fā)和業(yè)務人員通過這樣的觀測能力可以實時掌握軟件的運行情況,并獲得前所未有的關聯(lián)分析能力,以便不斷優(yōu)化業(yè)務的健康度和用戶體驗。
3、框架持續(xù)演進如今,技術與業(yè)務都發(fā)展非???,后端框架也會在一定范圍內(nèi)不斷升級重構,以適應變化的技術和業(yè)務需求。本框架設計都是面向服務接口調(diào)用,未來可能也會引入消息驅動設計,處理一些異步化的場景, 甚至重構升級為事件驅動的架構。當然,在業(yè)務高速迭代的情況下, 也需要考慮架構演進與業(yè)務發(fā)展之間的平衡。
希望以上內(nèi)容能對有需要的人有所幫助
歡迎大家留言寫下自己希望了解的技術方向
歡迎大家一起探討交流