摘自《Java微服務分布式架構企業實戰》
1 Spring Boot
Spring Boot是用於構建微服務的基礎框架,可以輕松地整合Spring Cloud實現系統服務化,在學習微服務之前學習Spring Boot的使用是非常有必要的,而且 Spring Boot與Spring MVC框架技術無縫銜接,使用自動化配置替代了原本需要手動完成的樣板化配置,摒棄之前開發過程中繁多的配置文件,測試部署起來也更加便捷。
Spring技術的出現,顛覆了傳統的Java EE技術,如今Spring Boot框架的出現簡化了Spring應用程序的開發,開箱即用,非常方便。相信大家都聽說過“習慣優於配置”這句話,該框架采用了特定的方式進行配置,因此,程序員在開發的過程中無須再進行樣板化配置,只需要少量配置和少量代碼就能完成,使得開發更加簡單、快速、方便。而且 Spring Boot內嵌 Servlet(Tomcat)容器,可以直接啟動運行項目。Spring至今已經發行多個版本,而且版本更新迭代也非常迅速,下面列舉版本更新的過程中的重要變更。
1.Spring 1.x時代
在Spring1.x時代,都是通過XML文件配置Bean,隨着項目的不斷擴大,需要將XML配置分放到不同的配置文件中,需要頻繁地在Java類和XML配置文件中切換。
2.Spring 2.x時代
隨着JDK 1. 5帶來的注解支持,Spring 2.x可以使用注解對Bean進行聲明和注入,大大地減少了XML配置文件,同時也大大簡化了項目的開發。
3.Spring 3.x時代
從Spring 3.x開始提供了Java配置方式,使用Java配置方式可以更好地理解配置的Bean,並且 Spring 4.x和Spring Boot都推薦使用Java配置的方式,之前的XML配置將會被Java配置替換掉。
4.Spring 5.x時代
Spring 5.x是Java界首個支持響應式的Web框架,是Spring的一個重要版本,距離Spring 4.x差不多四年。在此期間,大多數增強都是在Spring Boot項目中完成的,其最大的亮點就是提供了完整的端到端響應式編程的支持(新增 Spring WebFlux模塊)。
Spring WebFlux同時支持使用舊的Spring MVC 注解聲明 Reactive Controller.和傳統的MVC Controller 不同、Reactive Controller操作的是非阻塞的ServerHttpRequest和ServerHttpResponse,而不再是Spring MVC里的 HttpServletRequest和HttpServletResponse.至此也代表着Java正式迎來了響應式異步編程的時代。
在之前開發的過程中,通常會有以下幾步來完成:
(1)配置web.xml,加載Spring和Spring MVC;
(2)配置數據庫連接、配置Spring事務;
(3)配置加載配置文件的讀取,開啟注解;
(4)配置日志文件。
配置完成之后部署Tomcat調試,但是如果使用Spring Boot將會變得更加簡單,只需要非常少的幾個配置就能夠迅速地搭建起來一套Web項目或者構建一個微服務。
5.Spring Boot的優缺點
優點:快速構建項目,對主流開發框架的無配置集成,項目可獨立運行,無須外部依賴Servlet容器,提供運行時的應用監控,極大地提高了開發、部署效率,與雲計算的天然集成等。
缺點:版本迭代速度很快,一些模塊改動很大,由於不用自己做配置,報錯時很難定位,網上現成的解決方案比較少等。
2.Spring Cloud
在分布式、微服務系統中,當客戶端或者API網關想要訪問一個服務時,面對那么多的服務,怎樣能夠動態地准確獲取某個服務的IP和端口成了一個挑戰,此時提出服務注冊與發現機制-每一個服務自動把自己的IP和端口注冊到一個專門的服務器上,讓調用方能夠從計算機名或者應用ID、應用名稱方便地調用到需要調用的服務,就可以很好地解決這個問題。
Spring Cloud是一個提供了全套的分布式系統解決方案的微服務框架,它雖然是Spring 家族的新成員,但是更新的速度特別快。Spring Cloud為開發人員提供了一系列分布式系統的解決方案,包括配置管理、服務注冊與發現、路由、控制總線、全局鎖等,同時Spring Cloud還能夠快速地對接雲服務平台,快速地啟動服務、構建應用,有了這些方案,讓開發分布式系統更加簡單,使開發人員真正享受到“開箱即用”特性所帶來的便捷。
3.Netfix Eureka
Spring Cloud Netfix的Eureka是一個服務注冊和發現模塊,它的作用與ZooKeeper的作用相似。在微服務的開發過程中服務的治理是非常核心的模塊,一個大型的應用程序通常由非常多的服務構成,然而每個服務不一定都會部署在一台服務器上,因此客戶端在請求服務時通常要對服務的地址和IP進行解析,如圖6. 6所示。
Spring Cloud 是使用 Netfix Eureka來實現服務注冊與發現的,Netfix Eureka 中不僅包含了客戶端也有服務端。服務端稱為服務注冊中心,持續提供服務的發現和注冊。客戶端是通過注解在應用程序代碼中開啟的,當應用程序運行時,會將自身提供的服務注冊到Eureka服務端,同時通過持續周期性地發送心跳來判定服務是否一直可用,還會將從服務注冊中心查詢到的服務IP、端口等相關信息緩存到本地。
4.Eureka高可用集群
對於微服務系統來說,所有的服務都將會注冊到注冊中心,Eureka的可用性關乎整個應用程序能否繼續正常地提供服務,一旦部署Eureka服務的機器發生宕機或一些網絡因素的影響將可能致使整個應用處於癱瘓狀態。因此,Eureka通常在企業的實際部署過程中都是以集群形式存在的,這樣即使一個節點癱瘓,還有其他節點保證服務的可用性,降低了風險。
Eureka的高可用實際上就是把一個或多個Eureka Server當作一個普通的服務,將Eureka Server本身像其他服務一樣注冊到另一個Eureka Server中,使服務注冊中心達到相互注冊的目的,這些注冊中心的數據都是同步的,因此無論哪一個注冊中心存在故障,都可以繼續使用其他的處於存活狀態的Eureka Server.
5.Spring Cloud 創建服務消費者(Ribbon)
微服務是面向服務進行開發的,一個個服務之間的聯系也是錯綜復雜的,隨着項目的深人或者水平擴展,服務與服務之間就像蜘蛛網一樣交織在一起,管理起來也會愈發困難,所以能夠讓服務的消費者更簡單地調用服務,也是非常重要的。Spring Cloud也提供了相應的解決方案,能夠使服務的調用輕松地實現REST模板請求,還能做到負載均衡的效果。
Spring Cloud Ribbon 是基於Netflix Ribbon實現的HTTP和TCP客戶端負載均衡工具框架。在微服務項目中服務之間的調用、API Gateway的請求都是通過Ribbon(或者對Ribbon進一步的封裝框架)實現的。
(1)RestTemplate 詳解
Ribbon是通過 RestTemplate+@LoadBalance實現的,Spring為創建REST API提供了良好的支持,將資源的狀態以最適合的形式進行傳遞。借助RestTemplate,Spring 應用能夠方便地使用REST資源,Spring的 RestTemplate 訪問使用了模板方法的設計模式。下面將詳細介紹 RestTemplate實現不同請求和參數的服務調用。
6.負載均衡策略
負載均衡在分布式系統中尤為重要,可以使系統實現高可用、提高系統的處理能力。實現負載均衡的方式有很多,包括硬件負載均衡和軟件負載均衡。軟件負載均衡的實現通常通過相應的模塊來處理完成請求分發的功能,如反向代理負載均衡服務Nginx等,如圖7. 1所示。
在部署單台服務器時,如果這個服務器宕機了,那么用戶自然也無法繼續訪問了,如果同時有很多用戶試圖訪問服務器,超過了服務器本身處理能力的上限,就會出現加載速度緩慢或無法繼續提供服務的情況。為了應對這種情況,可以將服務同時部署在多台服務器中,當客戶端發起請求時,可以使用負載均衡服務作為一個請求訪問節點,負載均衡服務器根據相應的策略(如輪詢、權重、隨機等)來指定提供服務的服務器。這樣一來,可以防止單點故障或服務效率低下的問題發生,接下來將通過實例了解Ribbon中實現負載均衡的方式。
7.Spring Cloud 創建服務消費者Feign
Ribbon的使用,在服務的調度方面都會利用RestTemplate的攔截來實現接口的調用,它使用HttpClient或RestTemplate 模擬HTTP請求,調用的過程中步驟非常煩瑣,而Feign是對Ribbon的進一步封裝,簡化了編寫步驟,使用起來更加方便,接下來將學習聲明式服務調用Feign的使用。
Feign是一個聲明式的REST客戶端,它的目的就是讓REST風格的API調用變得更加簡單。使用Feign,只需要創建一個接口並加上注解來配置就可以實現服務提供者的接口綁定。它具有可插拔的注解特性,而且擴展了對 SpringMVC注解的支持,它本身就是對Ribbon的進一步封裝,因此同樣具備負載均衡調用。Feign會完全代理 HTTP請求,只需要像調用方法一樣調用它就可以完成服務請求及相關處理。
8.使用Hystrix 服務容錯保護
微服務架構中,服務被拆分得很細,每個服務都不在一個進程中,網絡的不穩定性則會造成服務在遠程調用的過程中出現故障或延遲的情況發生。由於HTTP請求是同步的,如果不采取補救措施,服務調用方會一直處在等待的地步。后續的請求一旦造成積壓,線程同步就會造成阻塞,阻塞就會引起服務雪崩的效應,最終導致服務癱瘓。面對這種問題,Spring Cloud也給出了解決方案-Spring Cloud Hystrix熔斷器的使用。
(1)熔斷器簡介
在微服務架構中,根據業務來拆分成一個個的服務,服務與服務之間可以通過RPC相互調用,在Spring Cloud中可以用RestTemplate+Ribbon和Feign來調用。為了保證其高可用,單個服務通常會集群部署。由於網絡原因或者自身的原因,服務並不能保證100%可用,如果單個服務出現問題,調用這個服務就會出現線程阻塞,此時若有大量的請求涌入,Servlet容器的線程資源會被消耗完畢,導致服務癱瘓。由於服務與服務之間的依賴性,故障會傳播,會對整個微服務系統造成災難性的嚴重后果,這就是服務故障的“雪崩”效應。為了解決這個問題,業界提出了熔斷器模型。
Netflix開源了 Hystrix組件,實現了熔斷器模式,Spring Cloud對這一組件進行了整合。在微服務架構中,一個請求需要調用多個服務是非常常見的,如圖7. 9所示。
請求通過瀏覽器或移動端發送至API網關,調用服務A、服務B、服務C、服務D四個服務,而服務A又會繼續調用服務AI,較底層的服務AI如果出現故障則不能及時返回結果,而服務A此時也沒有做服務降級處理,可能會導致服務A甚至整個系統的癱瘓。為了避免這種情況的發生可以在系統設計時使用一定的降級策略,保證即使出現某個服務提供方的服務不可用,即服務的調用的不可用達到一個閾值(Hystrix是5秒20次)時,熔斷器將會打開,服務調用方仍然可以切換到降級后的策略繼續執行,如圖7. 10所示。
圖7. 10中,當服務AI出現故障后,服務熔斷開啟,服務A和服務AI之間啟動斷路器熔斷機制,為了避免連鎖故障,還可以通過Fallback()方法直接返回一個固定值,接下來將結合案例講解熔斷器的使用。
9.路由網關分布式配置
在微服務架構中,需要幾個基礎的服務治理組件,包括服務注冊與發現、服務提供、服務消費、負載均囊、熔斷器、智能路由、配置管理等,這幾個基礎組件相互協作,共同組建了一個簡單的微服務系統,本章將繼續學習路由網關服務和分布式配置中心的實現。
(1)如果選擇將原有的單體應用構建成一組微服務時,首先就要考慮如何解決程序的客戶端與服務之間進行交互的問題,如果一個微服務架構的應用中有很多服務,那么客戶端與微服務之間要想直接通信必然要在客戶端存儲每個服務的IP和端口,當系統規模不斷增大時,服務也會越來越多,顯然這種做法是不現實的。因此,需要使用API網關服務器統一維護服務的IP和端口,這樣不僅可以完成請求路由的功能,還能實現負載均衡、驗證過濾等其他功能,一個簡單的微服務系統如圖8. 1所示。
在圖8. 1中的Spring Cloud微服務系統中,一種常見的負載均衡方式是,客戶端的請求首先經過負載均衡(Ngnix),再到達服務網關(Zuul集群),然后再到具體的服務。所有的服務將會統一注冊到高可用的服務注冊中心集群中,服務的所有的配置文件將交由配置服務來統一管理,配置服務的配置文件放在Git倉庫,方便開發人員可以隨時更改配置文件。Spring Cloud Zuul和Eureka結合,將自身服務注冊到Eureka服務注冊中心,同時獲取到其他服務的實例信息。
Zuul的主要功能是路由轉發和過濾器。路由功能是微服務的一部分,如通過REST接口訪問/api/user就可以將請求轉發到User服務,訪問/api/shop就可以將請求轉發到Shop服務。Zuul默認和Ribbon結合實現了負載均衡的功能。
10.Spring Cloud服務追蹤
隨着項目的不斷擴展,微服務的問題也會不斷地顯現出來,一個客戶端請求在調用服務得到返回結果的過程中,也許會形成一條復雜的調用鏈路,一個服務可能會有多個鏈路依賴,幾個服務協同完成。這樣一來,如果其中一條鏈路發生故障或者出現延遲,都可能會引起請求的失敗。這時,就可以通過實現對請求調用的追蹤來迅速發現故障,監控每條鏈路的性能並及時地排查解決問題。
1)ZipKin簡介
ZipKin是一個開放源代碼的分布式跟蹤系統,由Twitter公司研發,它致力於收集服務的定時數據,以解決微服務架構中的延遲問題,包括數據的收集、存儲、查找和展現。它的理論模型來自於Google Dapper的論文。
每個服務向ZipKin報告計時數據,ZipKin會根據調用關系通過ZipKin UI生成依賴關系圖,顯示了多少跟蹤請求通過每個服務,該系統讓開發者可通過一個Web前端輕松地收集和分析數據,例如用戶每次請求服務的處理時間等,可方便地監測系統中存在的瓶頸。
微服務架構是通過業務來划分服務的,使用REST調用。對外暴露的一個接口,可能需要很多個服務協同才能完成這個接口功能,如果鏈路上任何一個服務出現問題或者網絡超時,都會形成導致接口調用失敗。隨着業務的不斷擴張,服務之間互相調用會越來越復雜,如圖9. 1所示。