Spring Cloud(八)Zuul路由閘道器
阿新 • • 發佈:2018-11-02
文章目錄
1 概述
1.1 什麼是Zuul
Zuul是所有裝置和網站請求Netflix流應用程式後端的前門。作為一個邊緣服務應用程式,Zuul旨在實現動態路由,監控,彈性和安全性。它還可以恰當的將請求路由到多個Amazon彈性叢集中。
1.2 為什麼要建造Zuul
大量不同的Netflix API流量有時會導致迅速而無預警地出現問題。我們需要一個能夠迅速改變行為的系統,以應對這些情況。
1.3 Zuul有哪些功能
Zuul使用一系列不同型別的過濾器,使我們能夠快速靈活地將這些功能應用於我們的邊緣服務。這些過濾器可幫助我們執行以下功能:
- Authentication and Security(身份驗證和安全性 ):識別每個資源的認證要求並拒絕不滿足它們的請求。
- Insights and Monitoring(洞察和監控 ): 在邊緣跟蹤有意義的資料和統計資料,以便給我們一個準確的生產檢視。
- Dynamic Routing(動態路由):根據需要動態地向不同的後端叢集路由請求。
- Stress Testing(壓力測試):逐漸向叢集增加流量壓力來評估效能。
- Load Shedding(甩負荷):為每種型別的請求分配容量,並刪除超出限制的請求。
- Static Response handling(靜態響應處理):直接在邊緣建立一些響應,而不是將它們轉發到內部叢集。
- Multiregion Resiliency(多區域彈性):跨越AWS區域路由請求,以使我們ELB的使用多樣化,並使我們的優勢更靠近我們的成員。
1.4 理解
- Zuul路由功能負責將外部的請求轉發到具體的微服務例項上,是實現外部訪問統一入口的基礎。而過濾功能負責隊請求的處理過程進行干預,是實現請求校驗、服務聚合等功能的基礎。
- Zuul需要和Eureka整合,將Zuul註冊為Eureka服務治理下的應用,同時從Eureka中獲取其它微服務的訊息,即以後對微服務的訪問都通過Zuul跳轉後獲得。
- Zuul就像大樓的保安,你可以請他找人(代理),找的人在外面叫什麼名字(路由),是否允許你進入大樓(過濾)。因為保安屬於物業公司,所以保安要在物業公司註冊,所獲得的資訊也來源於物業公司(與Eureka的關係)。
2 Zuul路由功能
2.1 建立zuul服務
- 匯入依賴。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
</dependencies>
- 配置檔案。
server:
port: 9999
spring:
application:
name: spring-cloud-zuul-gateway #為這個服務取名,非常重要!!!!!
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: zuul.com
prefer-ip-address: true
- 修改hosts檔案。
127.0.0.0 zuul.com
- 建立主啟動類,並加入@EnableZuulProxy註解。
@SpringBootApplication
@EnableZuulProxy
public class SpringCloudZuulApplication9999 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZuulApplication9999.class, args);
}
}
2.2 測試
- 依次啟動uereka、一個provider、zuul服務,可以看到註冊了兩個微服務。
- 通過http://[服務ip]:[服務埠]/[路徑] 訪問,訪問成功。
- 通過http://[閘道器服務ip]:[閘道器服務埠]/[微服務名稱]/[路徑] 訪問,訪問成功。
可以理解為,Zuul在微服務裡找到了名為spring-cloud-provider的微服務,然後通過改為服務的訪問路徑訪問服務
2.3 路由訪問對映規則
2.3.1 修改配置檔案
server:
port: 9999
spring:
application:
name: spring-cloud-zuul-gateway #為這個服務取名,非常重要!!!!!
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: zuul.com
prefer-ip-address: true
zuul:
ignored-services: spring-cloud-provider #禁止通過微服務名訪問,可以使用萬用字元*
prefix: /mysevice #訪問字首,如果沒有該配置,則訪問路徑不能以/zuul/開頭
routes:
spring-cloud-provider: /myzuul/** #routes引數格式為Map,前者是key 為被代理服務名-spring-cloud-provider,後者是value為代理路徑-/myzuul/** ;可以配置多個服務代理
#spring-cloud-provider1: /myzuul1/**
2.3.2 修改後測試
重行啟動zuul服務,訪問:http://zuul.com:9999/mysevice/myzuul/hello/jack
證明:只能通過http://[閘道器服務ip]:[閘道器服務埠]/[字首][自己設定的路徑]/[路徑] 進行訪問,不加字首或者通過服務名訪問都失敗。
3 自定義zuul過濾器
3.1 編寫程式碼
//使該類成為配置類,注入spring容器
@Configuration
public class MyZuulFilter extends ZuulFilter {
/**
* pre:在請求路由之前執行過濾。我們可利用這種過濾器實現身份驗證、在叢集中選擇請求的微服務、記錄除錯資訊等。
* route:這種過濾器將請求路由到微服務。這種過濾器用於構建傳送給微服務的請求,並使用Apache HttpClient或Netfilx Ribbon請求微服務。
* post:這種過濾器在路由到微服務以後執行。這種過濾器可用來為響應新增標準的HTTP Header、收集統計資訊和指標、將響應從微服務傳送給客戶端等。
* error:在其他階段發生錯誤時執行該過濾器。
* 除了預設的過濾器型別,Zuul還允許我們建立自定義的過濾器型別。例如,我們可以定製一種STATIC型別的過濾器,直接在Zuul中生成響應,而不將請求轉發到後端的微服務。
* to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
* "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
* We also support a "static" type for static responses see StaticResponseFilter.
* Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
*
* @return A String representing that type
*/
@Override
public String filterType() {
return "pre";
}
/**
* 必須定義過濾器順序,如果該過濾器的優先順序不是很重要,過濾器順序命令可以相同,過濾器命令不需要是連續的。
* 命令從0,1,2...優先順序依次降低
* filterOrder() must also be defined for a filter. Filters may have the same filterOrder if precedence is not
* important for a filter. filterOrders do not need to be sequential.
* @return the int order of a filter
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 返回true run()方法將要執行,false將不執行,可以作為run() 方法執行開關。
* a "true" return from this method means that the run() method should be invoked
* @return true if the run() method should be invoked. false will not invoke the run() method
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 可以自己編寫任意的業務邏輯
* if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter
* @return Some arbitrary artifact may be returned. Current implementation ignores it.
*/
@Override
public Object run() {
System.out.println("shouldFilter() is true");
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
String requestURL = request.getRequestURL().toString();
int index = requestURL.lastIndexOf('/')+1;
String username = requestURL.substring(index);
//判定長度小於三為非法使用者名稱
if (username.length() >2 ) {
return true;
}else{
throw new RuntimeException("非法使用者名稱,請檢查!");
}
}
}
Zuul中預設實現了DebugFilter、StaticResponseFilter等過濾器,具體資訊可以看原始碼,可以以以下方式禁用某種過濾器
zuul:
FormBodyWrapperFilter:
pre:
disable: true
3.2 測試
4 整合Feign Hystrix,通過客戶端訪問
4.1 新建consumer hystrix zuul服務(複製consumer hystrix)
改寫feign呼叫介面。
@FeignClient(name= "spring-cloud-zuul-gateway", fallback = HelloRemoteFallback.class)
public interface HelloRemote {
String zuulUrlPrefix = "/mysevice/myzuul";
@RequestMapping(value = zuulUrlPrefix+"/hello/{name}")
String hello(@RequestParam(value = "name") String name);
}
4.2 測試
- 依次啟動uereka、provider、zuul、consumer hystrix zuul服務。
- 訪問:http://localhost/consumer/hello/jack
- 訪問:http://localhost/consumer/hello/ja
5 Zuul 服務降級
Zuul 是一個代理服務,如果被代理的服務突然宕機(如停掉provider 8001服務),那麼zuul將會報錯。但是consumer hystrix zuul服務已經有Feign降級服務,所以該服務不會報錯,所有隻有zuul報錯,因此應該配置zuul的降級服務。
5.1 新建MyZuulFallbackProvider類,並加入容器
//注入容器
@Component
public class MyZuulFallbackProvider implements ZuulFallbackProvider {
/**
* 必須設定好處理的失敗的服務路由
* @return
*/
@Override
public String getRoute() {
return "spring-cloud-provider";
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
/**
* 服務呼叫失敗後返回
* @return
* @throws IOException
*/
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("被代理服務故障,此結果由Zuul Gateway靜態提供!".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders() ;
headers.set("Content-Type", "text/html; charset=UTF-8");
return headers;
}
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.BAD_REQUEST.getReasonPhrase();
}
@Override
public void close() {
}};
}
}
5.2 測試
- 停掉provider 8001服務,訪問:http://localhost/consumer/hello/jack
- 訪問:http://zuul.com:9999/mysevice/myzuul/hello/jack
原始碼地址