翁湦元,單杏花,閻志遠(yuǎn),王雪峰
(中國鐵道科學(xué)研究院集團(tuán)有限公司 電子計(jì)算技術(shù)研究所,北京 100081)
鐵路站車Wi-Fi運(yùn)營服務(wù)平臺(tái)上線以來,先后增加了設(shè)備狀態(tài)監(jiān)控、運(yùn)營數(shù)據(jù)監(jiān)控、用戶行為分析以及手機(jī)App接入服務(wù)等功能。隨著系統(tǒng)功能的日益增加,系統(tǒng)應(yīng)用的數(shù)量不斷增多,原有應(yīng)用的體積不斷增長,應(yīng)用部署和維護(hù)的難度也隨之增長[1]。為實(shí)現(xiàn)業(yè)務(wù)的快速迭代,減少研發(fā)、部署和維護(hù)的復(fù)雜性,利用微服務(wù)架構(gòu)對(duì)現(xiàn)有系統(tǒng)進(jìn)行改造[2]。在微服務(wù)系統(tǒng)架構(gòu)中,獨(dú)立部署在不同進(jìn)程中的服務(wù)之間通過HTTP 等通信機(jī)制實(shí)現(xiàn)相互調(diào)用,從而實(shí)現(xiàn)系統(tǒng)的靈活部署和擴(kuò)展[3]。本文闡述了鐵路站車Wi-Fi運(yùn)營服務(wù)平臺(tái)進(jìn)行微服務(wù)化改造的架構(gòu)設(shè)計(jì)、關(guān)鍵問題和實(shí)施效果。
原鐵路站車Wi-Fi運(yùn)營服務(wù)平臺(tái)根據(jù)不同的業(yè)務(wù)需求垂直劃分為相互獨(dú)立的模塊,模塊均是單體應(yīng)用的形式,通過部署多個(gè)副本并借助Nginx負(fù)載均衡實(shí)現(xiàn)應(yīng)用服務(wù)能力的擴(kuò)展。單體應(yīng)用內(nèi)部功能集中,代碼和數(shù)據(jù)中心化,運(yùn)行在同一個(gè)進(jìn)程中。隨著業(yè)務(wù)系統(tǒng)功能的增多,一旦出現(xiàn)缺陷,原因難以定位。修復(fù)系統(tǒng)需要花費(fèi)較長的時(shí)間,項(xiàng)目構(gòu)建和部署的時(shí)間也會(huì)相應(yīng)加長。
通過引入微服務(wù)架構(gòu)模式,將應(yīng)用程序分解為一系列較小的互連服務(wù),從而避免大而臃腫的單體應(yīng)用架構(gòu)。根據(jù)既有系統(tǒng)業(yè)務(wù)進(jìn)行梳理,對(duì)平臺(tái)進(jìn)行服務(wù)拆分,拆分結(jié)果如表1所示。
表1 平臺(tái)服務(wù)列表
鐵路站車Wi-Fi運(yùn)營服務(wù)平臺(tái)可劃分為接入層、業(yè)務(wù)層、基礎(chǔ)資源層和數(shù)據(jù)層[4],微服務(wù)架構(gòu)設(shè)計(jì)如圖1所示。
圖1 微服務(wù)架構(gòu)設(shè)計(jì)圖
(1)接入層面向用戶和外部軟件以Web頁面或API接口的方式提供服務(wù),根據(jù)業(yè)務(wù)模塊垂直劃分,通過整合業(yè)務(wù)層內(nèi)各業(yè)務(wù)微服務(wù)的能力來為外部用戶和軟件提供最終的服務(wù),靈活地對(duì)服務(wù)進(jìn)行編排、組合,以實(shí)現(xiàn)快速迭代,滿足多變的外部需求。
(2)業(yè)務(wù)層由經(jīng)過拆分的相互獨(dú)立且松散耦合的服務(wù)組成,各服務(wù)專注于自身負(fù)責(zé)的模塊業(yè)務(wù)[5],可快速水平擴(kuò)展,同時(shí)服務(wù)的升級(jí)也不會(huì)影響平臺(tái)整體業(yè)務(wù)的正常運(yùn)行。
(3)基礎(chǔ)資源層由與業(yè)務(wù)無關(guān)的組件組成,為微服務(wù)應(yīng)用提供必要的運(yùn)行支撐。
(4)數(shù)據(jù)層部署的是各業(yè)務(wù)服務(wù)所需的數(shù)據(jù)庫實(shí)例,并且可以針對(duì)各業(yè)務(wù)的需求特性單獨(dú)配置數(shù)據(jù)復(fù)制和數(shù)據(jù)拆分等優(yōu)化策略。
微服務(wù)架構(gòu)相對(duì)于單體架構(gòu)而言更為復(fù)雜,以下針對(duì)微服務(wù)化改造中的若干關(guān)鍵問題和應(yīng)對(duì)措施進(jìn)行闡述。
微服務(wù)架構(gòu)中應(yīng)用的數(shù)量比單體架構(gòu)要多出許多,各應(yīng)用配置均不相同,配置的維護(hù)和管理難度變大。為此引入配置中心,將應(yīng)用的配置信息統(tǒng)一存儲(chǔ)在配置中心內(nèi)。各應(yīng)用只要注冊(cè)并加入微服務(wù)體系中,即可根據(jù)自身的服務(wù)名稱獲取相應(yīng)的配置信息,有效減少了配置出錯(cuò)的可能性。
圖2 微服務(wù)配置調(diào)用示意圖
如圖2所示,應(yīng)用通過注冊(cè)找到配置中心服務(wù),讀取自己的配置信息并完成啟動(dòng)流程,還可通過消息隊(duì)列監(jiān)聽配置信息的變化,完成配置的及時(shí)刷新。
微服務(wù)架構(gòu)是分布式的,服務(wù)都被部署在不同的節(jié)點(diǎn)中,而用戶的一次操作可能涉及多個(gè)服務(wù)處理。對(duì)于研發(fā)人員而言,調(diào)試過程中如何通過日志檢查各服務(wù)的運(yùn)行狀態(tài),分析用戶一次操作請(qǐng)求的處理過程將變得極為困難[6]。通過建立ELK(Elastic Search, Logstash, Kibana)[7]實(shí)現(xiàn)日志的集中采集和快速搜索服務(wù),并通過Zipkin實(shí)現(xiàn)服務(wù)調(diào)用鏈路的追蹤服務(wù),可解決日志查詢和調(diào)用過程的追蹤問題。日志采集與鏈路追蹤系統(tǒng)部署結(jié)構(gòu)示意圖,如圖3所示。
圖3 日志采集與鏈路追蹤示意圖
服務(wù)在運(yùn)行過程中的日志被Logstash采集組件搜集并通過Kafka消息隊(duì)列投送到Elastic Search集群中被索引以便快速檢索。服務(wù)之間的調(diào)用過程信息通過RabbitMq隊(duì)列投送至Zipkin鏈路追蹤服務(wù)中,Zipkin服務(wù)將信息保存至Elastic Search集群以供鏈路追蹤分析。
與傳統(tǒng)的單體程序不同,微服務(wù)架構(gòu)下用戶使用的每一功能都有可能涉及多個(gè)服務(wù)。若將用戶身份認(rèn)證整合進(jìn)每一個(gè)微服務(wù)應(yīng)用,會(huì)使得代碼出現(xiàn)大量冗余,增加代碼維護(hù)工作量。并且反復(fù)處理用戶認(rèn)證信息也是對(duì)計(jì)算資源的一種浪費(fèi)。為解決上述問題,引入JWT(Json Web Tokens)[8]身份認(rèn)證機(jī)制,并將JWT的認(rèn)證與API網(wǎng)關(guān)相結(jié)合,JWT認(rèn)證流程如圖4所示。
圖4 JWT認(rèn)證機(jī)制示意圖
通過網(wǎng)關(guān)對(duì)用戶操作的統(tǒng)一攔截與處理,對(duì)于免驗(yàn)證的接口請(qǐng)求直接放行,對(duì)于需要用戶身份認(rèn)證的接口請(qǐng)求,則解析并驗(yàn)證JWT信息是否有效,若JWT信息有效,往下轉(zhuǎn)發(fā)用戶請(qǐng)求,同時(shí)將用戶信息附加在請(qǐng)求頭中;若JWT信息無效,則拒絕用戶的請(qǐng)求。通過網(wǎng)關(guān)控制和JWT認(rèn)證統(tǒng)一全平臺(tái)的用戶權(quán)限控制機(jī)制,實(shí)現(xiàn)單點(diǎn)登陸,減少代碼冗余。
在微服務(wù)架構(gòu)內(nèi),應(yīng)用之間通過HTTP方式進(jìn)行交互[9],相比于單體應(yīng)用體系,微服務(wù)體系服務(wù)之間的依賴更加復(fù)雜,若按照以往的開發(fā)方式常常出現(xiàn)由于缺乏接口文檔或者接口文檔更新不及時(shí)導(dǎo)致開發(fā)人員使用錯(cuò)誤的方式調(diào)用服務(wù)接口的情況,研發(fā)人員不得不頻繁針對(duì)接口問題進(jìn)行溝通和代碼調(diào)整,增加了開發(fā)和溝通成本。為避免以上問題,將服務(wù)接口定義體現(xiàn)在interface中,并將這些接口獨(dú)立建立為API項(xiàng)目。服務(wù)提供方按照interface[10]中的定義實(shí)現(xiàn)Controller,服務(wù)調(diào)用方在Http客戶端中繼承對(duì)應(yīng)的interface,從而保證了雙方通信接口定義的統(tǒng)一。部分項(xiàng)目代碼如下。
(1)在api項(xiàng)目中編寫接口約定interface
api項(xiàng)目中僅編寫interface代碼,約定接口的Http調(diào)用地址和參數(shù)等信息。
(2)在服務(wù)提供方的Controller中編寫接口實(shí)現(xiàn)
服務(wù)提供方中用于接收和處理請(qǐng)求的Controller必須實(shí)現(xiàn)api項(xiàng)目中的interface,以保證接口按照interface的約定提供服務(wù)。
(3)在服務(wù)調(diào)用方按照interface的約定進(jìn)行調(diào)用
在調(diào)用方項(xiàng)目中,我們利用Spring Cloud組件中的Feign Client來進(jìn)行Http調(diào)用。Feign Client通過繼承api項(xiàng)目中的interface即可按照interface約定的地址和參數(shù)進(jìn)行調(diào)用。
綜上,通過公用interface代碼,保證了接口提供方和調(diào)用方對(duì)于某接口定義的一致性,從而避免了不必要的接口文檔編寫和溝通成本。
改造后的鐵路站車Wi-Fi運(yùn)營服務(wù)平臺(tái)充分利用了微服務(wù)架構(gòu)的優(yōu)勢(shì),能夠快速響應(yīng)需求變化,穩(wěn)定運(yùn)行的同時(shí)也可以實(shí)時(shí)監(jiān)控平臺(tái)各服務(wù)的運(yùn)行狀態(tài),應(yīng)用后的具體效果體現(xiàn)如下。
平臺(tái)運(yùn)行期間,在兩個(gè)月內(nèi)迅速地完成交易服務(wù)的研發(fā),并通過整合原有的內(nèi)容管理與展示服務(wù),成功上線小說收費(fèi)閱讀的功能,實(shí)現(xiàn)對(duì)原有的小說閱讀功能的平滑升級(jí)。如圖5所示,通過服務(wù)整合,內(nèi)容、用戶、交易3大服務(wù)模塊共同支撐內(nèi)容管理平臺(tái)的運(yùn)行。
圖5 服務(wù)整合實(shí)例圖
圖6展示了微服務(wù)平臺(tái)的全景調(diào)用關(guān)系圖、服務(wù)調(diào)用鏈時(shí)序圖、接口狀態(tài)監(jiān)測(cè)以及全局日志檢索功能。以上工具為研發(fā)人員快速調(diào)試、系統(tǒng)調(diào)優(yōu)提供了有力的支持。
圖6 研發(fā)調(diào)試工具實(shí)例圖
本文對(duì)微服務(wù)架構(gòu)進(jìn)行了簡(jiǎn)單介紹,闡述了鐵路站車Wi-Fi運(yùn)營服務(wù)平臺(tái)的原架構(gòu)設(shè)計(jì)的不足之處,提出了基于Spring Cloud的微服務(wù)架構(gòu)設(shè)計(jì)與改造方案,列舉了實(shí)施架構(gòu)改造的關(guān)鍵問題,并舉例說明了微服務(wù)化改造后的實(shí)施效果。微服務(wù)架構(gòu)的引入,使平臺(tái)得以快速響應(yīng)需求的變化,同時(shí)通過服務(wù)的拆分和解耦降低了研發(fā)人員的研發(fā)難度,監(jiān)控工具的引入也降低了研發(fā)人員的運(yùn)維成本。當(dāng)前架構(gòu)設(shè)計(jì)仍然存在不足,如對(duì)于Spring Cloud組件的依賴性強(qiáng),不利于引入多樣化的開發(fā)語言等。