上一篇簡單說了SpringCloud與Eureka的集成。主要解決了微服務間的服務註冊及調用的問題。這一篇集成Zuul,而後結合SpringCloud、Eureka、Zuul環境下進行真實系統聯調,幫助更好的對這些組件的理解。畢竟,實戰才是學習最快的方法。 一、聊聊網關 上篇也提到過,微服務下,各個 ...
上一篇簡單說了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模塊如果是部署集群網關該怎樣處理?他們之間的負載均衡策略又是怎樣的?連接超時、惡意訪問怎樣做熔斷限流?服務之間如何調用?),進行接近生產級項目的配置。敬請關註!
持續學習,記錄點滴。更多文章請訪問 文章首發