本文轉自:http://blog.csdn.net/qq_22841811/article/details/67637786#准備工作
1 API Gateway
2 Zuul介紹
2.1 zuul的功能
- Routing in an integral part of a microservice architecture. For example, / may be mapped to your web application, /api/users is mapped to the user service and /api/shop is mapped to the shop service. Zuul is a JVM based router and server side load balancer by Netflix.
- 路由在微服務架構的一個組成部分。 例如,/可以映射到您的Web應用程序,/ api / users映射到用戶服務,並且/ api / shop映射到商店服務。 Zuul是Netflix的基於JVM的路由器和服務器端負載均衡器。
- 其功能包括
- 驗證
- 見解
- 壓力測試
- 金絲雀測試
- 動態路由
- 服務遷移
- 減載
- 安全
- 靜態響應處理
- 主動/主動流量管理
- Zuul的規則引擎允許規則和過濾器基本上用任何JVM語言編寫,內置支持Java和Groovy。
2.2 Zuul的配置簡述
- 配置屬性zuul.max.host.connections已被兩個新屬性zuul.host.maxTotalConnections和zuul.host.maxPerRouteConnections替換,默認分別為200和20。
- 所有路由的默認Hystrix隔離模式(ExecutionIsolationStrategy)為SEMAPHORE。 如果首選此隔離模式,則可以將zuul.ribbonIsolationStrategy更改為THREAD。
2.3 在springcloud中使用zuul
- Spring Cloud創建了一個嵌入式Zuul代理,以簡化一個非常常見的用例開發,即UI應用程序想要代理對一個或多個后端服務的調用。此功能對於用戶界面代理所需的后端服務非常有用,從而避免了對所有后端獨立管理CORS和身份驗證問題。
- 要啟用它,使用@EnableZuulProxy注釋一個Spring Boot主類,並將本地調用轉發到相應的服務。按照慣例,ID為“users”的服務將從位於/ users處的代理(帶有前綴剝離)接收請求。代理使用Ribbon來定位要通過發現轉發的實例,並且所有請求都在hystrix命令中執行,因此故障將顯示在Hystrix指標中,一旦電路打開,代理將不會嘗試聯系服務。
- 注意:Zuul啟動器不包括發現客戶端,因此對於基於服務ID的路由,您需要在類路徑中提供其中一個(例如Eureka是一個選擇)。
3 Zuul的基本使用
- maven依賴
-
<?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>spring-cloud-microservice-study</artifactId> <groupId>com.clsaa.learn.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>microservice-gateway-zuul</artifactId> <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> </project>
- 啟動類
-
package com.clsaa.learn.zuul; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** 使用@EnableZuulProxy注解激活zuul。 * 跟進該注解可以看到該注解整合了@EnableCircuitBreaker、@EnableDiscoveryClient,是個組合注解,目的是簡化配置。 * Created by Egg on 2017/7/25 */ @SpringBootApplication @EnableZuulProxy public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class,args); } }
配置文件:application.yml
spring: application: name: microservice-gateway-zuul server: port: 8040 eureka: instance: hostname: localhost # 指定該Eureka實例的主機名 prefer-ip-address: true client: serviceUrl: defaultZone: http://username:password@localhost:8761/eureka
3.1 測試
- 啟動microservice-api-gateway項目。還記得我們之前訪問通過http://localhost:8000/1去訪問microservice-provider-user服務中id=1的用戶信息嗎?
我們現在訪問http://localhost:8050/microservice-provider-user/1試試。會驚人地看到:
{"id":1,"username":"Tom","age":12}
這不正是microservice-provider-user服務中id=1的用戶信息嗎?
所以我們可以總結出規律:訪問
http://GATEWAY:GATEWAY_PORT/想要訪問的Eureka服務id的小寫/**
將會訪問到http://想要訪問的Eureka服務id的小寫:該服務端口/**
4 自定義配置Zuul路由
上文我們已經完成了通過API Gateway去訪問微服務的目的,是通過http://GATEWAY:GATEWAY_PORT/想要訪問的Eureka服務id的小寫/**
的形式訪問的,那么如果我們想自定義在API Gateway中的路徑呢?譬如想使用http://localhost:8050/user/1
就能夠將請求路由到http://localhost:8000/1呢?
只需要做一點小小的配置即可:
spring:
application:
name: microservice-api-gateway
server:
port: 8050
eureka:
instance:
hostname: gateway
client:
serviceUrl:
defaultZone: http://discovery:8761/eureka/
# 下面整個樹都非必須,如果不配置,將默認使用 http://GATEWAY:GATEWAY_PORT/想要訪問的Eureka服務id的小寫/** 路由到:http://想要訪問的Eureka服務id的小寫:該服務端口/**
zuul:
routes:
user: # 可以隨便寫,在zuul上面唯一即可;當這里的值 = service-id時,service-id可以不寫。
path: /user/** # 想要映射到的路徑
service-id: microservice-provider-user # Eureka中的serviceId
5 如何忽略某些服務
准備工作
- 啟動服務:microservice-discovery-eureka
- 啟動服務:microservice-provider-user
- 啟動服務:microservice-consumer-movie-ribbon
如果我們現在只想將microservice-consumer-movie-ribbon服務暴露給外部,microservice-provider-user不想暴露,那么應該怎么辦呢?
依然只是一點小小的配置即可:
spring:
application:
name: microservice-api-gateway
server:
port: 8050
eureka:
instance:
hostname: gateway
client:
serviceUrl:
defaultZone: http://discovery:8761/eureka/
zuul:
ignored-services: microservice-provider-user # 需要忽視的服務(配置后將不會被路由)
routes:
movie: # 可以隨便寫,在zuul上面唯一即可;當這里的值 = service-id時,service-id可以不寫。
path: /movie/** # 想要映射到的路徑
service-id: microservice-consumer-movie-ribbon-with-hystrix # Eureka中的serviceId
- 也可使用ignoredServices:服務名
- 路由必須有一個“路徑”,可以指定為ant樣式模式,所以“/ myusers / ”只匹配一個級別,但“/ myusers / *”分層匹配。
- 后端的位置可以被指定為“serviceId”(對於來自發現的服務)或“url”(對於物理位置),例如。
-
zuul: routes: users: path: /myusers/** url: http://example.com/users_service
6 啟動Hystrixcommand
- 這些簡單的url路由不會作為HystrixCommand執行,也不能使用Ribbon來平衡多個URL。 要實現此目的,請指定服務路由並為serviceId配置功能區客戶端(這當前需要禁用功能區中的Eureka支持:有關詳細信息,請參閱上文)。
-
zuul: routes: users: path: /myusers/** serviceId: users ribbon: eureka: enabled: false users: #這是ribion要請求的serviceID ribbon: listOfServers: http://localhost:7900,http://localhost:7901
7 使用正則表達規則路由
- 可以使用regexmapper在serviceId和路由之間提供約定。 它使用正則表達式命名的組從serviceId提取變量並將它們注入到路由模式中。
- regexmapper:用於routepattern轉換為servicePattern
- routepattern:路由正則表達式
- servicePattern:service正則表達式
@Bean public PatternServiceRouteMapper serviceRouteMapper() { return new PatternServiceRouteMapper( "(?<name>^.+)-(?<version>v.+$)", "${version}/${name}"); }
- 這意味着serviceId“myusers-v1”將映射到路由“/ v1 / myusers / ”。 接受任何正則表達式,但所有命名組必須同時存在於servicePattern和routePattern中。 如果servicePattern與serviceId不匹配,則使用缺省行為。 在上面的示例中,serviceId“myusers”將映射到路由“/ myusers / ”(未檢測到任何版本)。此功能默認情況下處於禁用狀態,僅適用於發現的服務。
zuul:
ignoredPatterns: /**/admin/**
routes:
users: /myusers/**
-
This means that all calls such as “/myusers/101” will be forwarded to “/101” on the “users” service. But calls including “/admin/” will not resolve.
-
如果你需要你的路由以保留它們的順序,你需要使用YAML文件,因為使用屬性文件將會丟失順序。 例如:如果要使用屬性文件,則舊路徑可能會在用戶路徑前面顯示,導致用戶路徑無法訪問。
8 zuul.prefix
- 要向所有映射添加前綴,請將zuul.prefix設置為一個值,例如/ api。 默認情況下,在轉發請求之前,從請求中刪除代理前綴(使用zuul.stripPrefix = false關閉此行為)。
- prefix和stripPrefix(依賴於prefix的使用)連用影響是全局的
- path和stripPrefix連用影響是局部的
9 細節知識
9.1 routes
- 如果使用@EnableZuulProxy與Spring Boot Actuator,您將啟用(默認情況下)一個額外的端點,通過HTTP作為/ routes可用。 到此端點的GET將返回映射路由的列表。 POST將強制刷新現有路由(例如,如果服務目錄中有更改)。
9.2 Strangulation Patterns (絞殺者模式)
- 遷移現有應用程序或API時的常見模式是“扼殺”舊的端點,慢慢地用不同的實現替換它們。 Zuul代理是一個有用的工具,因為可以使用它來處理來自舊端點的客戶端的所有流量,但重定向一些請求到新的端點。
-
zuul: routes: first: path: /first/** url: http://first.example.com second: path: /second/** url: forward:/second third: path: /third/** url: forward:/3rd # 本地的轉發 legacy: path: /** url: http://legacy.example.com
9.3 fallback
- 在類中定制http返回的屬性
-
package com.clsaa.learn.zuul.fallback; import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @Component public class MyFallbackProvider implements ZuulFallbackProvider { @Override public String getRoute() { //route 如 return "microservice-provider-user"; } @Override public ClientHttpResponse fallbackResponse() { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "OK"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream(("fallback"+MyFallbackProvider.this.getRoute()).getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } }
9.4 使用sidecar支持異構語言
10過濾器
10.1過濾器類型與請求生命周期
-
Zuul大部分功能都是通過過濾器來實現的。Zuul中定義了四種標准過濾器類型,這些過濾器類型對應於請求的典型生命周期。
- PRE:這種過濾器在請求被路由之前調用。我們可利用這種過濾器實現身份驗證、在集群中選擇請求的微服務、記錄調試信息等。
- ROUTING:這種過濾器將請求路由到微服務。這種過濾器用於構建發送給微服務的請求,並使用Apache HttpClient或Netfilx Ribbon請求微服務。
- POST:這種過濾器在路由到微服務以后執行。這種過濾器可用來為響應添加標准的HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等。
- ERROR:在其他階段發生錯誤時執行該過濾器。
- 除了默認的過濾器類型,Zuul還允許我們創建自定義的過濾器類型。例如,我們可以定制一種STATIC類型的過濾器,直接在Zuul中生成響應,而不將請求轉發到后端的微服務。
10.2 編寫zuul過濾器
- 過濾器類
-
package com.clsaa.learn.zuul; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; @Component public class PreZuulFilter extends ZuulFilter{ private final static Logger LOGGER = LoggerFactory.getLogger(PreZuulFilter.class); @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 1;//數字越大越靠后 } @Override public boolean shouldFilter() { return true; } @Override public Object run() { HttpServletRequest servletRequest = RequestContext.getCurrentContext().getRequest(); String host = servletRequest.getRemoteHost(); PreZuulFilter.LOGGER.info("request host : " + host); return null; } }
10.3 禁用過濾器
479/5000
Zuul for Spring Cloud在代理和服務器模式下默認啟用了一些ZuulFilter bean。 有關已啟用的可能過濾器,請參閱zuul過濾器包。 如果你想禁用一個,只需設置:
zuul.<SimpleClassName>.<filterType>.disable=true
按照慣例,過濾器之后的包是Zuul過濾器類型。 例如,禁用
org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter set zuul.SendResponseFilter.post.disable = true