是什麼
說Zuul之前,我們先來說一下之前我們做過的項目架構,我們之前使用Eureka實現服務註冊中心以及服務註冊與發現功能,而服務間通過Ribbon或OpenFeign實現服務的消費以及均衡負載。爲了使得服務集羣更爲健壯,使用Hystrix的融斷機制來避免在微服務架構中個別服務出現異常時引起的故障蔓延。
在這樣的架構中,我們的服務集羣雖然註冊到了Eureka中,但是確實一個對外的服務,通過負載均衡公開至服務的調用方。這樣直接暴露我們的服務地址存在很大的不足:
-
破壞了服務無狀態特點。
爲了保證對外服務的安全性,我們需要實現對服務訪問的權限控制,而開放服務的權限控制機制將會貫穿並污染整個開放服務的業務邏輯,這會帶來的最直接問題是,破壞了服務集羣中REST API無狀態的特點。從具體開發和測試的角度來說,在工作中除了要考慮實際的業務邏輯之外,還需要額外考慮對接口訪問的控制處理。
-
無法直接複用既有接口。
當我們需要對一個即有的集羣內訪問接口,實現外部服務訪問時,我們不得不通過在原有接口上增加校驗邏輯,或增加一個代理調用來實現權限控制,無法直接複用原有的接口。
爲了解決上面的問題,服務網關出現了。
應用服務網關,可以將權限控制從服務單元中抽離出去,而最適合這些邏輯的地方就是處於對外訪問對前端的地方。服務網關是微服務架構中一個不可或缺的部分。通過服務網關統一向外系統提供REST API的過程中,除了具備服務路由
、均衡負載
功能之外,它還具備了權限控制
等功能。Spring Cloud Netflix中的Zuul就擔任了這樣的一個角色,爲微服務架構提供了前門保護的作用,同時將權限控制這些較重的非業務邏輯內容遷移到服務路由層面,使得服務集羣主體能夠具備更高的可複用性和可測試性。
我們看一下加入Zuul後的服務架構:
不管是來自於客戶端(PC或移動端)的請求,還是服務內部調用。一切對服務的請求都會經過Zuul這個網關,然後再由網關來實現 鑑權、動態路由等等操作。Zuul就是我們服務的統一入口。
實例
我們同樣應用之前案例中的微服務項目,在父工程中新建zuul工程。
(1)新建子工程
(2)導入依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>eureka-practice</artifactId>
<groupId>com.zhyheima.bj</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zuul</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
</project>
因爲zuul也是一個服務,並且需要定時拉取服務,所以我們也需要註冊到Eureka服務中心。
(3)編寫配置
server:
port: 10010 #服務端口
spring:
application:
name: zuul #指定服務名
eureka:
client:
register-with-eureka: true #是否 將自己注入到eureka
fetch-registry: true #是否從eureka服務中抓取已有的 註冊信息
service-url: #將生產者分別註冊到兩個服務中心
defaultZone: http://eureka10086.com:10086/eureka,http://eureka10087.com:10087/eureka
instance:
instance-id: zzhhyy:zuul10010 #注入到eureka後的id標識,不寫的標識爲ip地址
prefer-ip-address: true #訪問路徑可以顯示ip地址
#Eureka客戶端向服務端發送心跳的時間間隔,單位爲秒(默認是30秒)
lease-renewal-interval-in-seconds: 30
#Eureka服務端在收到最後一次心跳後等待時間上限 ,單位爲秒(默認是90秒),超時剔除服務
lease-expiration-duration-in-seconds: 90
(4)編寫引導類
package com.zhyheima.bj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableDiscoveryClient //開啓eureka客戶端
@EnableZuulProxy //開啓網關功能
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
我們重新啓動,查看eureka註冊中心中的信息,發現已經註冊成功:
(5)編寫路由規則
這裏我們配置面向服務的路由,根據服務的名稱,去eureka註冊中心查找服務對應的所有實例列表。
映射規則:
我們將/item/**開頭的請求,代理到以item-server爲服務名的服務中。
重啓zuul服務,輸入訪問地址:
http://localhost:10010/server/test/2
http://localhost:10010/consumer/test/2
查看訪問成功:
(6)路有前綴
配置示例:
zuul:
routes:
item-server: /server/** # 這裏是映射路徑
item-consumer: /consumer/**
prefix: /api # 添加路由前綴
我們通過zuul.prefix=/api
來指定了路由的前綴,這樣在發起請求時,路徑就要以/api開頭。