張 晶, 王琰潔, 黃小鋒(北京中電普華信息技術(shù)有限公司, 北京 009)(中國電建集團國際工程有限公司, 北京 00048)
一種微服務(wù)框架的實現(xiàn)①
張 晶1, 王琰潔1, 黃小鋒21(北京中電普華信息技術(shù)有限公司, 北京 100192)2(中國電建集團國際工程有限公司, 北京 100048)
相對于傳統(tǒng)單塊架構(gòu), 微服務(wù)框架具有技術(shù)選型靈活、獨立按需擴展、可用性高等優(yōu)點, 更適合當前互聯(lián)網(wǎng)時代需求. 但微服務(wù)架構(gòu)的應(yīng)用也會引入新的問題, 如跨進程通訊、服務(wù)注冊發(fā)現(xiàn)、分布式Session管理等.本文在對傳統(tǒng)框架和微服務(wù)框架進行分析比較的基礎(chǔ)上, 給出了微服務(wù)框架的一種實現(xiàn)方案. 該方案設(shè)計了微服務(wù)框架的功能架構(gòu), 對微服務(wù)框架引入的關(guān)鍵問題給出了解決方案. 采用該實現(xiàn)方案進行業(yè)務(wù)系統(tǒng)開發(fā), 開發(fā)人員只需要關(guān)注微服務(wù)內(nèi)部業(yè)務(wù)功能的開發(fā), 微服務(wù)之間的注冊、發(fā)現(xiàn)、監(jiān)控和Session管理由微服務(wù)框架完成,簡化了系統(tǒng)開發(fā)的難度, 提高開發(fā)效率.
微服務(wù)框架; 服務(wù)注冊; 服務(wù)發(fā)現(xiàn); Session管理
軟件的架構(gòu)設(shè)計是決定應(yīng)用系統(tǒng)是否能夠被正確、有效實現(xiàn)的關(guān)鍵要素之一. 架構(gòu)設(shè)計描述了在應(yīng)用系統(tǒng)的內(nèi)部, 如何根據(jù)業(yè)務(wù)、技術(shù)、組織, 以及靈活性、可擴展性、可維護性等多種因素, 將應(yīng)用系統(tǒng)劃分成不同的部分, 并使這些部分相互協(xié)作, 從而為用戶提供某種特定價值的方式[1,2].
傳統(tǒng)信息化系統(tǒng)的典型架構(gòu)是單塊架構(gòu), 即將應(yīng)用程序的所有功能都打包成一個應(yīng)用, 每個應(yīng)用是最小的交付和部署單元, 應(yīng)用部署后運行在同一進程中.典型的單塊架構(gòu)應(yīng)用, 如基于傳統(tǒng)J2EE平臺所構(gòu)建的產(chǎn)品或者項目, 它們存在的形態(tài)一般是WAR包或者EAR包. 當部署這類應(yīng)用時, 通常是將整個包作為一個整體, 部署在同一個WEB容器, 如Tomcat或者Jetty中. 當這類應(yīng)用運行起來后, 所有的功能也都運行在同一個進程中. 單塊架構(gòu)應(yīng)用具有IDE友好、易于測試和部署等優(yōu)勢, 但是, 隨著互聯(lián)網(wǎng)的迅速發(fā)展和企業(yè)應(yīng)用范圍的擴展, 單塊架構(gòu)表現(xiàn)出一些不足[3]:
①代碼龐雜, 理解困難, 新人上手也困難;
②維護困難, 一般由一個團隊維護, 應(yīng)用越大,則維護的人越多, 團隊管理成本也越高, 團隊效率也會
越低下;
③功能升級困難: 每一次小改動都需要重新部署整個應(yīng)用, 進行全面測試;
④技術(shù)堆棧固化: 嘗試新技術(shù)的代價太高, 導致技術(shù)僵化;
⑤擴展困難: 應(yīng)用某些部分偏IO密集型、某些部分卻偏CPU密集型, 但應(yīng)用卻只部署在一臺機器上,很難用單一硬件來滿足應(yīng)用各部分對硬件資源的不同要求.
如何找到一種更有效的、更靈活、更適應(yīng)當前互聯(lián)網(wǎng)時代需求的系統(tǒng)架構(gòu)方式, 成為大家關(guān)注的焦點.隨著微服務(wù)架構(gòu)的出現(xiàn)以及在國內(nèi)外的成功應(yīng)用, 基于微服務(wù)框架構(gòu)建系統(tǒng)應(yīng)用成為一種新的選擇.
微服務(wù)架構(gòu)是一種架構(gòu)模式, 采用一組服務(wù)的方式來構(gòu)建一個應(yīng)用, 服務(wù)獨立部署在不同的進程中,不同服務(wù)通過一些輕量級交互機制來通信, 例如RPC、HTTP 等, 服務(wù)可獨立擴展伸縮, 每個服務(wù)定義了明確的邊界, 不同的服務(wù)甚至可以采用不同的編程語言來實現(xiàn), 由獨立的團隊來維護[4].
相對于傳統(tǒng)的單體應(yīng)用架構(gòu), 微服務(wù)架構(gòu)通過將功能分解到各個離散的服務(wù)實現(xiàn)對應(yīng)用系統(tǒng)的解耦,具有明顯的優(yōu)勢[5,6]:
①復雜度可控: 每一個微服務(wù)專注于單一功能,并通過定義良好的接口清晰表述服務(wù)邊界, 體積小、復雜度低, 提高了系統(tǒng)的可維護性和開發(fā)效率.
②獨立部署: 微服務(wù)具備獨立的運行進程, 可以獨立部署. 當某個微服務(wù)發(fā)生變更時無需編譯、部署整個應(yīng)用. 由微服務(wù)組成的應(yīng)用相當于具備一系列可并行的發(fā)布流程, 使得發(fā)布更加高效, 同時降低對生產(chǎn)環(huán)境所造成的風險, 最終縮短應(yīng)用交付周期.
③技術(shù)選型靈活: 每個團隊可以根據(jù)自身服務(wù)的需求和行業(yè)發(fā)展的現(xiàn)狀, 自由選擇最適合的技術(shù)棧.
④容錯: 在微服務(wù)架構(gòu)下, 故障被隔離在單個服務(wù)中. 可通過重試、平穩(wěn)退化等機制實現(xiàn)應(yīng)用層面的容錯, 避免全局性的不可用.
⑤ 擴展: 每個服務(wù)可以根據(jù)實際需求獨立進行擴展.
采用微服務(wù)架構(gòu)也會引入新的問題: 基于微服務(wù)架構(gòu)的應(yīng)用是分布式系統(tǒng), 服務(wù)獨立運行在不同的進程中, 需要有進程間通訊機制來支撐服務(wù)之間的交互;應(yīng)用由多個服務(wù)構(gòu)成, 每個服務(wù)可以有多個實例, 當一項服務(wù)存在于多個主機節(jié)點時, 需要一套服務(wù)發(fā)現(xiàn)機制,使服務(wù)調(diào)用端可以獲取正確的服務(wù)地址; 微服務(wù)應(yīng)用是分布式系統(tǒng), 需要解決分布式系統(tǒng)中Session管理的問題.這些都是在微服務(wù)框架實現(xiàn)時需要解決的問題.
通過對微服務(wù)框架進行分析, 確定了微服務(wù)框架的總體架構(gòu), 如圖1所示.
圖1 架構(gòu)圖
微服務(wù)框架包括服務(wù)注冊發(fā)現(xiàn)、日志管理、序列化、服務(wù)配置、服務(wù)容器、服務(wù)通信、限流容錯、管理接口和服務(wù)安全等組件.
其中, 服務(wù)容器是微服務(wù)運行的容器, 通過內(nèi)嵌服務(wù)器的方式實現(xiàn). 包含界面展現(xiàn)組件、IOC組件、數(shù)據(jù)持久化組件支撐業(yè)務(wù)系統(tǒng)的功能開發(fā). 界面展現(xiàn)組件提供用于界面設(shè)計的通用組件, 支持主流瀏覽器兼容性、可視化編程、控件拖拽等功能. IOC組件提供依賴注入功能, 管理程序依賴. 數(shù)據(jù)持久化組件負責微服務(wù)數(shù)據(jù)的持久化存儲.
日志管理: 記錄重要的框架層日志、度量和調(diào)用鏈數(shù)據(jù), 同時將日志、度量等接口暴露出來, 讓業(yè)務(wù)層能根據(jù)需要記錄業(yè)務(wù)日志數(shù)據(jù).
序列化: 支持將業(yè)務(wù)邏輯以REST或者RPC方式暴露出來, 支持可定制的序列化機制. 對瀏覽器, 框架支持輸出Ajax友好的JSON消息格式; 而對無線設(shè)備上的Native App, 框架支持輸出性能高的Binary消息格式.
服務(wù)配置: 支持文件方式配置, 集成動態(tài)運行時配置, 能夠在運行時針對不同環(huán)境動態(tài)調(diào)整服務(wù)的參數(shù)和配置.
服務(wù)通信: 提供基于REST/RPC的同步請求響應(yīng)模式和基于消息的異步通信模式.
限流和容錯: 集成限流容錯組件, 能夠在運行時自動限流和容錯, 保護服務(wù). 同時和動態(tài)配置相結(jié)合,實現(xiàn)動態(tài)限流和熔斷.
管理接口: 提供管理接口, 可以在線查看框架和服務(wù)內(nèi)部狀態(tài), 同時還可以動態(tài)調(diào)整內(nèi)部狀態(tài), 對調(diào)試、監(jiān)控和管理提供快速反饋.
服務(wù)安全: 以插件方式封裝安全和訪問控制邏輯,業(yè)務(wù)服務(wù)根據(jù)需要加載相關(guān)安全插件.
2.1 服務(wù)注冊發(fā)現(xiàn)
微服務(wù)架構(gòu)是由一系列職責單一的細粒度服務(wù)構(gòu)成的分布式網(wǎng)狀結(jié)構(gòu), 一個服務(wù)可以多實例并存, 這就引入了服務(wù)注冊發(fā)現(xiàn)問題, 服務(wù)提供者要注冊發(fā)布服務(wù)地址, 服務(wù)消費者要能發(fā)現(xiàn)目標服務(wù), 同時服務(wù)提供者一般以集群方式提供服務(wù), 也就引入了負載均衡問題. 目前主要的服務(wù)注冊發(fā)現(xiàn)方案有兩種:
①提供者服務(wù)發(fā)現(xiàn)
在服務(wù)提供者和服務(wù)消費者之間有一個獨立的負載均衡器, 負載均衡器上有所有服務(wù)的地址映射表.當服務(wù)消費者調(diào)用某個目標服務(wù)時, 向負載均衡器發(fā)送請求, 負載均衡器根據(jù)策略做負載均衡后將請求轉(zhuǎn)發(fā)到目標服務(wù). 這種方式實現(xiàn)簡單, 服務(wù)消費者無需實現(xiàn)服務(wù)發(fā)現(xiàn)邏輯, 但系統(tǒng)中需要維護一個高可用的負載均衡組件. 另外, 負載均衡組件在服務(wù)消費者和服務(wù)提供者之間增加了一跳, 有一定性能開銷.
②消費者服務(wù)發(fā)現(xiàn)
服務(wù)消費者要訪問某個服務(wù)時, 通過內(nèi)置的負載均衡組件向服務(wù)注冊表查詢目標服務(wù)地址列表, 然后以某種負載均衡策略選擇一個目標服務(wù)地址, 最后向目標服務(wù)發(fā)起請求. 這一方案需要一個服務(wù)注冊表配合服務(wù)注冊和發(fā)現(xiàn), 一般采用高可用、分布式一致的組件如Zookeeper、Consul、Etcd等來實現(xiàn). 原理如圖2所示.
圖2 消費者服務(wù)發(fā)現(xiàn)
和方案一相比, 該方案將服務(wù)發(fā)現(xiàn)能力分散到每一個服務(wù)消費者的進程內(nèi)部, 同時服務(wù)消費方和服務(wù)提供方之間是直接調(diào)用, 沒有額外開銷, 性能比較好.
微服務(wù)框架在實現(xiàn)時采用消費者服務(wù)發(fā)現(xiàn)的方式.
2.2 會話管理
基于微服務(wù)框架的系統(tǒng)是一個分布式系統(tǒng), 用戶的一個請求可能跨越多個微服務(wù), 而且一個服務(wù)可部署多個實例, 因此需要實現(xiàn)分布式環(huán)境下的Session管理, 以解決Session ID共享、Session數(shù)據(jù)復制及Session生命周期管理等問題.
在分布式環(huán)境中, Session管理通常有三種方式: Session復制、粘性Session和緩存集中式管理. Session復制, 將一臺機器上的Session數(shù)據(jù)廣播復制到集群中其它機器上; 粘性Session, 當用戶訪問集群中某臺機器后, 強制指定后續(xù)所有請求均落到此機器上; 緩存集中式管理, 將Session存入分布式緩存中, 當用戶訪問不同節(jié)點時先從緩存中獲取Session信息. 這三種方式的對比如表1所示.
表1 三種方式對比
為適應(yīng)復雜的網(wǎng)絡(luò)環(huán)境, 提高Session管理的可靠性, 在微服務(wù)框架實現(xiàn)時采用緩存集中式管理方式進行Session的管理.
3.1 基礎(chǔ)框架
目前開源的微服務(wù)框架主要有Dropwizard和SpringBoot. 兩個框架在實現(xiàn)技術(shù)上存在一定差異[7],如表2所示.
表2 Dropwizard和SpringBoot對比
Spring boot聚焦于Spring應(yīng)用, 可以借力Spring家族體系的其它成員, 完成通信、數(shù)據(jù)訪問等功能, 體系龐大沉重; DropWizard從前端網(wǎng)頁、核心服務(wù)、資料庫存取到資源監(jiān)控, 提供了一個輕量級的開發(fā)架構(gòu),更適用于云開發(fā)環(huán)境. 為了保持微服務(wù)輕量級特性及向云環(huán)境部署遷移, 應(yīng)用框架在實現(xiàn)上選取了DropWizard框架.
DropWizard是一個后臺服務(wù)開發(fā)框架, 內(nèi)置jetty服務(wù)器, 封裝jersey容器, 幫助開發(fā)者快速的打造一個Rest風格的后臺服務(wù), 同時集成hibernate4、log4j、slf4j、jackson等開源組件. DropWizard結(jié)構(gòu)的微服務(wù)主要包括四部分[8]:
①Configuration/config.yml: 用于微服務(wù)配置信息的定義和讀取.
②Application: 該服務(wù)的主入口, 定義服務(wù)使用的配置文件, 開放Resource, 創(chuàng)建數(shù)據(jù)庫連接對象等.
③Resource: 定義一個資源, 包括如何獲取該資源, 對該資源進行g(shù)et、post請求時對應(yīng)的業(yè)務(wù)邏輯.
④HealthCheck: 隨時檢測當前服務(wù)是否可用.
Dropwizard框架本身缺少依賴注入的支持, 在微服務(wù)框架中對Dropwizard進行改造, 引入輕量級依賴注入框架Google Guice[9], 簡化系統(tǒng)開發(fā)的難度. 整合代碼如表3所示.
表3 整合Google Guice代碼
3.2 服務(wù)注冊發(fā)現(xiàn)
消費者服務(wù)發(fā)現(xiàn)需要一個服務(wù)注冊表, 采用開源組件Consul來實現(xiàn). 相對于Zookeeper、Etcd等其它服務(wù)注冊組件, Consul具有以下優(yōu)點[10]: 支持多數(shù)據(jù)中心下分布式高可用的服務(wù)發(fā)現(xiàn)和配置共享; 成員管理和消息廣播采用Gossip協(xié)議, 去中心化; 支持健康檢查, 允許鍵值對存儲; 支持ACL訪問控制. 服務(wù)注冊發(fā)現(xiàn)的架構(gòu)如圖3所示.
圖3 服務(wù)注冊發(fā)現(xiàn)架構(gòu)圖
微服務(wù)啟動時, 將服務(wù)信息注冊到consulClient, consulClient將注冊信息提交給consulServer, consulServer將信息提交給consulLeader, consulLeader將自身的數(shù)據(jù)復制給其他的consulServer, 實現(xiàn)所有服務(wù)信息同步. 當微服務(wù)B訪問微服務(wù)A時, 首先從consulServer上獲取微服務(wù)A所有可用的服務(wù)地址,根據(jù)負載均衡策略選擇一個進行訪問, 訪問的過程中通過熔斷器來進行超時容錯處理.
Consul采用Go語言進行編寫, 引入開源的consul-client庫實現(xiàn)Java對Consul的訪問. 在微服務(wù)啟動的時候進行服務(wù)注冊, 注冊代碼如表4所示.
AgentClient agentClient = consul.agentClient(); try { agentClient.register(prop.getServicePort(), URI.create(prop.getHealthUrl()).toURL(), prop.getHealthInterval(), prop.getServicename(), prop.getServicename(), // serviceId: prop.getServiceTag()); } catch (MalformedURLException e) { logger.error ("服務(wù)注冊異常: " + e.printStackTrace()); }
3.3 Session管理
為了解決分布式環(huán)境中Session共享的問題, 微服務(wù)框架在實現(xiàn)時選擇分布式緩存方式進行Session的管理. 通過對網(wǎng)絡(luò)I/O模型、內(nèi)存管理、數(shù)據(jù)一致性、存儲方式等方面對開源的分布式緩存組件進行對比,最終選擇redis作為緩存組件.redis是一個開源的Key-Value存儲系統(tǒng), 具有快速、支持數(shù)據(jù)類型豐富、所有操作都是原子操作等優(yōu)點. 同時使用Haproxy組件實現(xiàn)負載均衡和redis故障遷移, 保證Session信息的高可用性. 架構(gòu)如圖4所示.
圖4 Session管理架構(gòu)圖
當redis master故障時, 通過haproxy設(shè)置redis slave為臨時master, redis master重新恢復后, 再切換回去. redis-master與redis-slave雙向同步, 解決redis單點問題.
Session共享原理: 借助HttpServletRequest Wrapper對HttpServletRequest對象進行包裝, 覆蓋getSession()方法, 接管創(chuàng)建和管理Session的工作. 通過Filter, 完成請求包裝操作, 并觸發(fā)事件完成Session的保存. Session保存流程如圖5所示.
圖5 Session保存流程
圖6 Session獲取流程
由于對HttpServletRequest進行了包裝, 當系統(tǒng)中獲取Session時, 調(diào)用包裝類的getSession方法從redis緩存中獲取Session, 流程如圖6所示.
微服務(wù)框架已經(jīng)在國家電網(wǎng)統(tǒng)一應(yīng)用開發(fā)平臺V2.9.0版本中實現(xiàn), 該版本經(jīng)過第三方安全、性能測試, 于2016年7月27日正式發(fā)版. 目前, 已選中兩個項目組進行框架的試點應(yīng)用.
本文對目前流行的微服務(wù)框架進行分析, 提出了一種微服務(wù)框架的實現(xiàn)方案. 該方案設(shè)計了微服務(wù)框架的功能架構(gòu), 重點分析了微服務(wù)架構(gòu)所帶來的服務(wù)注冊、服務(wù)發(fā)現(xiàn)、Session管理等問題, 并給出了實現(xiàn)方案. 基于該微服務(wù)框架進行業(yè)務(wù)系統(tǒng)開發(fā), 開發(fā)人員只需要關(guān)注微服務(wù)內(nèi)部業(yè)務(wù)功能的開發(fā), 微服務(wù)之間的注冊、發(fā)現(xiàn)、監(jiān)控和Session管理由微服務(wù)框架完成, 簡化了系統(tǒng)開發(fā)難度, 提高開發(fā)效率.
1 溫昱.軟件架構(gòu)設(shè)計:程序員向架構(gòu)師轉(zhuǎn)型必備.北京:電子工業(yè)出版社,2012.
2 王磊.解析微服務(wù)架構(gòu)(一)單塊架構(gòu)系統(tǒng)以及其面臨的挑戰(zhàn)[2015-05-11].http://www.infoq.com/cn/articles/analysis-thearchitecture-of-microservice-part-01.
3 Richardson C. Introduction to Microservices [2015-05-19]. https://www.nginx.com/blog/introduction-to-microservices/
4 Fowler M, Lewis J. Microservices. [2014-03-25]. http:// martinfowler.com/articles/microservices.html.
5 Parmar K. Microservice Architecture-A Quick Guide [2014-06]. http://www.kpbird.com/2014/06/microservice-architecture-quick-guide.html.
6 Richardson C. Introduction to Microservices [2015-05-19]. https://www.nginx.com/blog/introduction-to-microservices/.
7 Ullah R. Dropwizard vs Spring Boot—A Comparison Matrix. https://dzone.com/articles/dropwizard-vs-spring-boot? utm_source=tuicool&utm_medium=referral,2015-02-02.
8 Yammer.Getting Started.http://www.dropwizard.io/0.9.1/docs/ getting-started.html.
9 Sameb. Getting Started. [2014-07-08]. https://github.com/ google/guice/wiki/GettingStarted.
10 HashiCorp. Introduction to Consul. https://www.consul.io/ intro/index.html.
Implementation of Microservice Architecture
ZHANG Jing1, WANG Yan-Jie1, HUANG Xiao-Feng21(Beijing China Power Information Technology Co. Ltd., Beijing 100192, China)2(Power China International Group Limited, Beijing 100048, China)
Compared with traditional monolithic architecture, microservice architecture has many advantages, such as flexible technology selection, independent scalability, high availability and so on, and is more suitable for the current needs of the Internet age. But microservice architecture also introduces new problems, such as cross-process communication, service registration, service discovery, and distributed session management. On the basis of analysis and comparison between the traditional framework and microservice framework, this paper shows one implementation method of microservice framework. First, we design a scheme of microservices architecture framework and the functional framework, and then give the solutions of some key issues that microservice architecture introduces. With this scheme, developers only need to focus on the development of business functions, service registration, discovery, monitoring and session management provided by the framework to simplify the development and improve development effectiveness.
microservice architecture; service registration; service discover; session management
2016-07-21;收到修改稿時間:2016-08-18
10.15888/j.cnki.csa.005684