Zuul 微服務網關
作用:
Zuul的核心其實就是一系列過濾器
-身份認證與安全
-審查與監控
-動態路由
-壓力測試
-負載分配
-靜態響應處理
-多區域彈性
加入Zuul后的軟件架構:
Zuul的spring依賴自帶了springweb依賴,因此建項目時只要導入Zuul依賴即可
引入eureka客戶端依賴,以拉取客戶端列表
在主類上加入注解:
@EnableZuulProxy //開啟Zuul的網關功能
配置文件:
server:
port: 10010
spring:
application:
name: zuul
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
zuul:
routes:
user-uservice: /user-service/** #這是默認的路由條目,只要zuul連上eureka就會獲取eureka上的服務列表,並且根據這個服務列表提供所有服務的自動配置,而且此默認的路由一直都存在,即:不管你寫不寫,都有這條
user-service: /user/** #訪問地址為127.0.0.1:10010/user/user/16
ignored-services: #這里是不路由的服務,書寫方式是集合的方式
- consumer-service
去除路由前綴:
server:
port: 10010
spring:
application:
name: zuul
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
zuul:
routes:
user-service:
path: /user/**
serviceId: user-service
strip-prefix: false //去除路由前綴,默認為true,改為false即使user-serivce這條路由的/user路徑不做去除,發送給真實路徑,則訪問地址為127.0.0.1:10010/user/16,因為匹配路徑的/user/會發送給真實路徑,但使用此功能無法簡化路由條目配置
ignored-services: #這里是不路由的服務,書寫方式是集合的方式
- consumer-service
過濾器:
ZuulFilter是過濾器的頂級父類。在這里我們看一下其中定義的4個最重要的方法:
public abstract ZuulFilter implements IZuulFilter{ abstract public String filterType(); abstract public int filterOrder(); boolean shouldFilter();// 來自IZuulFilter Object run() throws ZuulException;// IZuulFilter }
-
shouldFilter
:返回一個Boolean
值,判斷該過濾器是否需要執行。返回true執行,返回false不執行。 -
run
:過濾器的具體業務邏輯。 -
filterType
:返回字符串,代表過濾器的類型。包含以下4種:-
pre
-
routing
:在路由請求時調用 -
post
:在routing和errror過濾器之后調用 -
error
:處理請求時發生錯誤調用
-
-
filterOrder
:通過返回的int值來定義過濾器的執行順序,數字越小優先級越高。
過濾器執行的生命周期:
-
-
請求到達首先會經過pre類型過濾器,而后到達routing類型,進行路由,請求就到達真正的服務提供者,執行請求,返回結果后,會到達post過濾器。而后返回響應。
-
-
異常流程:
-
整個過程中,pre或者routing過濾器出現異常,都會直接進入error過濾器,再error處理完畢后,會將請求交給POST過濾器,最后返回給用戶。
-
如果是error過濾器自己出現異常,最終也會進入POST過濾器,而后返回。
-
-
Zuul所有內置過濾器列表:
使用場景:
-
-
異常處理:一般會在error類型和post類型過濾器中結合來處理。
-
自定義過濾器:
模擬一個登錄的校驗。
基本邏輯:如果請求中有access-token參數,則認為請求有效,放行。
@Component public class LoginFilter extends ZuulFilter{ @Override public String filterType() { // 登錄校驗,肯定是在前置攔截 return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { // 該常量值為5 ,減1后為4 return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { // 返回true,代表過濾器生效。 return true; } @Override public Object run() throws ZuulException { // 登錄校驗邏輯。 // 1)獲取Zuul提供的請求上下文對象 RequestContext ctx = RequestContext.getCurrentContext();//RequestContext是一個Request域,此域的作用范圍是從請求到達zuul一直到路由結束返回到客戶端,整個完整流程都會存在 // 2) 從上下文中獲取request對象 HttpServletRequest req = ctx.getRequest(); // 3) 從請求中獲取token String token = req.getParameter("access-token"); // 4) 判斷 if(StringUtils.isBlank(token)){ //StringUtils,需引apache的commons-lang3包的依賴 使用此方式可以避免內存溢出 // 沒有token,登錄校驗失敗,攔截 ctx.setSendZuulResponse(false);//true則放行,false則攔截 // 返回403狀態碼。也可以考慮重定向到登錄頁。 ctx.setResponseStatusCode(HttpStatus.Forbidden.value()); } // 校驗通過,可以考慮把用戶信息放入上下文,繼續向后執行 return null;//默認為空即為放行 } }
此時使用http://127.0.0.1:10010/user/16 網頁會跳轉403
使用http://127.0.0.1:10010/user/16?access-token=1212121 即可正常訪問,此案例只是驗證access-token是否存在,不驗證access-token的正確性
Zuul的負載均衡ribbon和熔斷hystrix
在zuul的配置文件中配置
server:
port: 10010
spring:
application:
name: zuul
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
zuul:
routes:
user-service:
path: /user/**
serviceId: user-service
strip-prefix: false
ignored-services:
- consumer-service
zuul: retryable: true ribbon: ConnectTimeout: 250 # 連接超時時間(ms) ReadTimeout: 2000 # 通信超時時間(ms) OkToRetryOnAllOperations: true # 是否對所有操作重試 MaxAutoRetriesNextServer: 2 # 同一服務不同實例的重試次數 MaxAutoRetries: 1 # 同一實例的重試次數 hystrix: command: default: execution: isolation: thread: timeoutInMillisecond: 6000 # 熔斷超時時長:6000ms
由於ribbon一次訪問失敗后會自動重試一次,因此 ( ConnectTimeout + ReadTimeout ) × 2 < timeoutInMillisecond
即:
timeoutInMillisecond的真實值是: ( ConnectTimeout + ReadTimeout ) × 2
公式:
timeoutInMillisecond = ( ribbon ConnectTimeout + ribbon ReadTimeout ) * (maxAutoRetries + 1) * ( maxAutoRetriesNextServer + 1 );