Zuul的核心時一系列的過濾器Filter來實現的,zuul的全部功能都是基於過濾器去實現的。web
Zuul一共有四種不一樣的生命週期的Filter,分別是:算法
pre:在Zuul按照規則路由到下級服務以前執行。若是須要對請求進行預處理,好比鑑權,限流等,都應該考慮在此類Filter實現。spring
route:這個類Filter是Zuul路由動做的執行者,是Apache HttpClient或Netflix Ribbon構建和發送原始HTTP請求的地方法,目前支持OkHttp。數據庫
post:這類Filter是在源服務返回結果或者異常信息發生後執行,若是須要對返回信息作一些處理,則在此類Filter進行處理。api
error:在整個生命週期內若是發生異常,則會進入error Filter,可作全局異常處理。網絡
在實際項目中,每每須要自實現以上類型的Filter來對請求鏈路進行處理,根據業務的需求,選取相應的生命週期的Filter來達成目的。在Filter之間,經過RequestContext類老進行通訊,內部採用ThreadLocal保存你沒給請求的一些信息,包括請求路由,錯誤信息,HttpServletRequest,HttpServletResponse,這使得一些操做時十分可靠的,它還擴張了ConcurrentHashMap,目的時爲了在處理工程中保存各類形式的信息。app
若是使用@EnableZuulProxy註解搭配Spring Boot Actuator,會看到管控的端點的信息,具體的配置以下:框架
添加依賴pom.xml:spring-boot
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
複製代碼
添加配置:工具
management:
endpoints:
web:
exposure:
include: "*" # * 在yaml 文件屬於關鍵字
複製代碼
訪問以下的地址能夠看到:
名稱 | 類型 | 次序 | 描述 |
---|---|---|---|
ServletDetectionFilter | pre | -3 | 經過Spring Dispatcher檢查請求是否經過 |
Servlet30WrapperFilter | pre | -2 | 適配HttpServletRequest爲Servlet30Wrapper對象 |
FormBodyWrapperFilter | pre | -1 | 解析表單數據爲下游請求從新編譯 |
DebugFilter | pre | 1 | Debug路由標識 |
PreDecorationFilter | pre | 5 | 處理請求上下文供後續使用,設置下游相關頭信息 |
RibbonRoutingFilter | route | 10 | 使用Ribbon,Hystrix或者嵌入式HTTP客戶端發送請求 |
SimpleHostRoutingFilter | route | 100 | 使用Apache的HttpClient發送請求 |
SendForwardFilter | route | 500 | 使用Servlet發送請求 |
SendResponseFilter | post | 1000 | 將代理請求的響應寫入當前響應 |
SendErrorFilter | error | 0 | 若是RquestContext.getThrowable()不爲空,則轉發到error,path配置的路徑 |
因爲以前的例子的啓動類使用了@EnbaleZuulProxy註解後安裝的Filter,若是使用了@EnaleZuulServer將缺乏PreDecorationFilter,RibbonRoutingFilter,SimpleHostRoutingFilter等過濾器
以上的過濾器類有可能並不必定可以知足咱們的須要,因此咱們能夠採起替代的方式,將其源碼覆蓋,也能夠採起禁用策略: zuul...disable=true,好比要禁用DebugFilter,只須要在配置文件添加以下的配置: zuul.DebugFilter.pre.disable=true.
在Zuul中實現自定義的Filter,咱們只須要集成ZuulFilter類便可,ZuulFilter是一個抽象類,咱們須要實現如下的幾個方法:
filterOrder():使用返回值設定Filter執行次序。
filterType():使用返回值攝動Filter類型,能夠是pre,route,post,error類型。
shouldFilter():使用返回值設定該Filter是否執行,能夠做爲開關使用。
run():Filter裏面的核心執行邏輯,業務處理在此編寫。
除了是上面的方法須要重寫以外,還須要把建立好的過濾器加入配置中,咱們能夠像下面把配置的加入內存中
@Configuration
public class ZuulFilterConfiguration {
@Bean
public FirstPreFilter firstPreFilter() {
return new FirstPreFilter();
}
@Bean
public SencodPreFilter sencodPreFilter() {
return new SencodPreFilter();
}
@Bean
public ThirdPreFilter thirdPreFilter(){
return new ThirdPreFilter();
}
@Bean
public PostFilter postFilter(){
return new PostFilter();
}
@Bean
public ErrorFilter errorFilter(){
return new ErrorFilter();
}
}
複製代碼
後臺打印的日誌以下:
限流的算法主要有兩種算法,分別以下:
漏桶算法:
漏桶算法(Leaky Bucket)是網絡世界中流量整形(Traffic Shaping)或速率限制(Rate Limiting)時常用的一種算法,它的主要目的是控制數據注入到網絡的速率,平滑網絡上的突發流量。漏桶算法提供了一種機制,經過它,突發流量能夠被整形以便爲網絡提供一個穩定的流量。
令牌算法:
令牌桶算法是網絡流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一種算法。典型狀況下,令牌桶算法用來控制發送到網絡上的數據的數目,並容許突發數據的發送。
顯示限流中咱們最經常使用的方式是定義Filter,而後加上上面的主要限流算法便可。在實際開發中咱們可使用別人現成的工具。spring-cloud-zuul-ratelimit,該框架主要用於提供Zuul的限流,該框架提供了不少細粒度的策略:
多種粒度臨時變量存儲方式
上面主要是一些關於spring-cloud-zuul-ratelimit的一些基本的只是,現實中須要怎麼使用?
pom的依賴
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
複製代碼
application.yml配置文件的配置
zuul:
ratelimit:
#按力度拆分的臨時變量key的前綴
key-prefix: springcloud-book
#啓動限流開關
enabled: true
#key的存儲類型默認是IN_MEMORY本地存儲,此外還有多種形式
repository: in_memory
#標識代理以後,能夠單獨細化到服務粒度
behind-proxy: true
#犬奴限流策略,可單獨細化到服務粒度
default-policy:
#在一個單位時間窗口內的請求數量
limit: 2
#在一個單位時間窗口內的請求時間限制
quota: 1
#單位時間窗口
refresh-interval: 3
type:
- user
- origin
- url
複製代碼
連續屢次請求能夠看到以下的結果:
Zuul的文件上傳直接沿用了Springboot的那一套,因此配置的時候也能夠想配置SpringBoot文件上傳那樣。
spring:
application:
name: zuul-server
servlet: #spring boot2.0以前是http
multipart:
enabled: true # 使用http multipart上傳處理
max-file-size: 100MB # 設置單個文件的最大長度,默認1M,如不限制配置爲-1
max-request-size: 100MB # 設置最大的請求文件的大小,默認10M,如不限制配置爲-1
file-size-threshold: 1MB # 當上傳文件達到1MB的時候進行磁盤寫入
location: / # 上傳的臨時目錄
##### Hystrix默認超時時間爲1秒,若是要上傳大文件,爲避免超時,稍微設大一點
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 30000
ribbon:
ConnectTimeout: 3000
ReadTimeout: 30000
複製代碼
Zuul內部默認使用了Ribbon來調用遠程服務,因此因爲Ribbon的緣由,在咱們部署好全部的組華南以後,第一次經歷zuul的調用每每會註冊中心讀取服務註冊表,初始化Ribbon負載信息,這是一種懶加載的策略,可是這個過程是很耗時的,尤爲是服務過多的時候,爲了不這個問題,咱們能夠在啓動的Zuul的時候就姐加載應用程序上下文信息,開啓飢餓加載咱們只須要配置配置文件。
zuul:
ribbon:
eager-load:
enabled: true #開啓飢餓加載
複製代碼
在Spring Cloud中有多種和發送Http請求的返回格式能夠與Zuul結合,Ribbon,Feign或者RestTemplate,可是不管選擇那種,均可以出現請求失敗的狀況,在複雜的網絡中是無可避免的。Zuul做爲uige網關中間件,在出現偶然請求失敗的時候進行適當的調整是頗有必要的,重試是能夠有效避免一些特殊狀況的引發的請求丟失的。
pom依賴:
<!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.4.RELEASE</version>
</dependency>
複製代碼
配置以下:
ribbon:
#重試機制配置
ConnectTimeout: 3000
ReadTimeout: 60000
MaxAutoRetries: 1 #對第一次請求的服務的重試次數
MaxAutoRetriesNextServer: 1 #要重試的下一個服務的最大數量(不包括第一個服務)
OkToRetryOnAllOperations: true
複製代碼