上一篇簡單說了SpringCloud與Eureka的集成,主要解決了微服務間的服務注冊及呼叫的問題,這一篇集成Zuul,而后結合SpringCloud、Eureka、Zuul環境下進行真實系統聯調,幫助更好的對這些組件的理解,畢竟,實戰才是學習最快的方法,
一、聊聊網關
上篇也提到過,微服務下,各個業務模塊都被拆分成相互獨立的微服務,雖然注冊中心(如Eureka)解決了服務內部的注冊發現、健康檢查等問題,但是如何與外部服務進行通信又是一個新的問題了,
舉個栗子
某初創公司,剛剛經歷了一次大的架構改革,將原有的單體架構分解成了很多的微服務進行獨立部署,這些微服務包括用戶鑒權系統、訂單系統、定時任務系統等等,而原有的JSP也被改造成基于HTML下的靜態頁面進行前后端分離部署,
那么問題來了,因為前后端是分開的,前端同學在呼叫后端不同服務時要定義各種不同的URI進行呼叫,管理起來太麻煩,而且,這種情況下一旦后端服務郵編,有需要重新對域名進行決議,這也側面增加了運維同學的作業量,而更可怕的是這又與現在大家都在提倡的DevOps完全相悖了,
二、說了這么多我用Nginx不就行了么
是的,用Nginx的確是能幫助解決服務統一入口的問題,但是因為Nginx比較偏運維性質,而且其路由配置全部都是基于組態檔的硬編碼方式進行處理,一旦后臺服務發生變化,配置也需要及時更改,這樣也沒有完全解決上述問題,
這時候,網關的出現讓我看到了曙光,通過服務名就可以進行路由轉發,熔斷限流,日志監控,最主要的是可以開發人員自己通過配置就能輕松實作,不用每次都求運維人員去做決議,這樣豈不是也是更符合DevOps了呢,
三、Zuul
Zuul簡單介紹
Zuul在英文中是怪獸的意思,寓意看門神獸,由大名鼎鼎的Netflix開源,并被Pivotal集成入Spring Cloud體系,當前流行的為1.X與2.X系列,主要區別為Zuul從2.X系列開始采用非阻塞異步模式,大大提升了其性能,他是基于filter機制進行作業,有統一入口、健康檢查、藍綠部署、金絲雀發布、日志監控、路由轉發等功能,也可集成Ribbon、Hystrix增加負載均衡、熔斷的功能,
Zuul架構

Spring Cloud Zuul
實際開發中可以根據選擇去集成Zuul網關,也可直接選擇Spring集成好的Spring Cloud Zuul方便更快的使用起來,本篇重點是集成Spring Cloud Zuul,
關于Spring Cloud Zuul與Netflix Zuul相比還是有些許不一樣的,他是基于SpringBoot + Netflix Zuul內核而成,去掉了原有的動態過濾器加載,所以生產環境中還是根據需要自己選擇,
四、話不多說請看代碼
老規矩,附上原始碼地址SpingCloud+Zuul+Eureka
操作步驟
-
還是在原來的spring-cloud-demo(上一篇地址SpringCloud+Eureka)專案上,右鍵創建一個新的model.具體步驟不再贅述,創建完成后專案結構如下:

-
引入Zuul依賴
主要依賴如下:<!-- 引入Zuul starter --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter</artifactId> </dependency> <!-- 連接Eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> -
創建業務模塊provider、consumer,方法跟上一步一樣,創建后專案結構如下:

- 其中provider為服務提供者,提供基礎服務的微服務
- consumer為服務的主要呼叫者,下一章會講服務之間基于介面(Feign)的呼叫
-
配置Zuul路由轉發以及ribbon、hystrix
spring.application.name = zuul-gateway logging.level.org.spring.framework.security = INFO #hystrix設定 時間要大于Ribbon時間總和 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds = 90000 eureka.instance.instance-id = ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/ #通過eureka發現的服務,使用ribbon ribbon.ReadTimeout = 20000 ribbon.ConnectTimeout = 20000 zuul.ignoredServices = '*' #設定不走ribbon的time-out時間 zuul.host.connect-timeout-millis = 20000 zuul.host.socket-timeout-millis = 20000 #只要訪問以/api/開頭的多層目錄都可以路由到服務名為kxtop-provider的服務上. zuul.routes.kxtop-provider.path = /api/** zuul.routes.kxtop-provider.service-id= kxtop-provider zuul.routes.kxtop-provider.stripPrefix = false #kxtop-consumer配置 zuul.routes.kxtop-consumer.path = /consumer/** zuul.routes.kxtop-consumer.service-id = kxtop-consumer zuul.routes.kxtop-consumer.stripPrefix = false server.port = 4000 management.endpoints.web.exposure.include = * -
創建Zuul啟動類
@EnableDiscoveryClient //作為Eureka發現者 @EnableZuulProxy //開啟Zuul @SpringBootApplication public class ZuulGatewayApplication { public static void main(String[] args) { SpringApplication.run(ZuulGatewayApplication.class); } } -
分別配置provider、consumer組態檔及啟動類
provider
spring.application.name = kxtop-provider server.port = 5000 eureka.instance.instance-id = ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/ logging.level.org.spring.framework.security = INFO server.servlet.context-path = /api management.endpoints.web.exposure.include = * ------------------------- @EnableDiscoveryClient @SpringBootApplication public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class); } }consumer
spring.application.name = kxtop-consumer server.port = 6000 eureka.instance.instance-id = ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/ logging.level.org.spring.framework.security = INFO server.servlet.context-path = /consumer management.endpoints.web.exposure.include = * -------------------------- @EnableDiscoveryClient @SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class); } } -
整體測驗
- 啟動Eureka并瀏覽器打開
localhost:8761

- 分別啟動專案Zuul、provider、consumer
- 保證每個服務都正常運行
- 服務埠對照
服務名 埠號 zuul-gateway 4000 provider 5000 consumer 6000
- 重繪瀏覽器查看效果(可以看到,服務都已經注冊成功且處于UP狀態)

- postman測驗網關呼叫
-
provider模塊新建TestGatewayController,并重啟provider
@RestController @RequestMapping("/test-gateway") public class TestGatewayController { @GetMapping public String testGateway() { return "Hi! 我是Consumer服務中的TestGatewayController."; } } -
訪問localhost:4000/api/test-gateway

-
出現上面這句話,訪問成功,請注意:我們訪問的是localhost的4000 埠,也就是配置的Zuul的埠哦,而輸出【Hi! 我是Consumer服務中的TestGatewayController】這句話的方法則是在埠為5000的consumer模塊中定義的,這就就證明我們以配置的網關和服務注冊發現是正確的,當然你也可以做更多的測驗,
- 啟動Eureka并瀏覽器打開
五、后續
下一篇會針對以上的整合做更加詳細的配置,我們會基于ZuulGateway去做更豐富測驗(比如provider、consumer模塊如果是部署集群網關該怎樣處理?他們之間的負載均衡策略又是怎樣的?連接超時、惡意訪問怎樣做熔斷限流?服務之間如何呼叫?),進行接近生產級專案的配置,敬請關注!
持續學習,記錄點滴,更多文章請訪問 文章首發
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/5987.html
標籤:架構設計
