7、Spring -Cloud-路由網管Spring Cloud Zuul
阿新 • • 發佈:2019-04-04
hystrix lose -s servle scope 容器 默認 type nbsp
7.1、為什麽需要Zuul
Zuul 作為路由網關組件,在微服務架構中有著非常重要的作用:
7.2、Zuul的工作原理
Zuul 是通過 Servlet 來實現的, Zuul 通過自定義的 Zuu!Servlet (類似於 Spring MVC的DispatcServlet )來對請求進行控制 Zuul 的核心是一系列過濾器 可以在 Http 請求的發起和響應返回期間執行 系列的過濾器。 包含以下四種過濾器:Zuul 采取了動態讀取、編譯和運行這些過濾器 過濾器 間不能直接相互通信,通過RequestContext 對象來共享數據 每個請求都會創建一個RequestContext 對象 特性:
請求的生命周期圖:
7.3、案例
7.3.1、搭建 Zuul 服務
新建一個項目:
pom文件:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
此時需要使用到的工程: 配置均是之前的配置:
spring.application.name=feign server.port=8087 eureka.client.service-url.defaultZone=http://localhost:8762/eureka/ #開啟Hystrix的功能 feign.hystrix.enabled=true
在下方配置文件的使用:
spring.application.name=hystric server.port=8088 eureka.client.service-url.defaultZone=http://localhost:8762/eureka/ #開啟Hystrix的功能 feign.hystrix.enabled=true
在下方配置文件的使用:
新建工程的配置類:
@EnableZuulProxy @EnableEurekaClient @SpringBootApplication public class EurekaZuulClientApplication { public static void main(String[] args) { SpringApplication.run(EurekaZuulClientApplication.class, args); } }
配置文件:
eureka: client: service-url: defaultZone: http://localhost:8762/eureka/ server: port: 5000 spring: application: name: zuul zuul: routes: #自定義的 ribbonapi: #路徑 path: /ribbonapi/** #引入的application(上述需要使用到的工程名) serviceid: hystric feignapi: path: /feignapi/** serviceid: feign
zuul.routes.ribbonapi中的ribbonapi時自己定義的 需要指定path和serviceId兩者配合使用 就可以將指定類型的請求url路由到制定的serviceId 即滿足/ribbonapi 開頭的請求Url都會被分發到hystric 服務 如果某個服務存在多個實例,Zul結合Ribbon會做負載均衡,將請求均分的部分路由到不同服務的實例。 此時也需要進行啟動上述的兩個工程,分別修改器端口號進行訪問測試: Eureka註冊中心:
兩個服務是可以進行訪問的
此時訪問: http://localhost:5000/ribbonapi/hi hi是之前的請求url
訪問:http://localhost:5000/feignapi/feign 這裏會有負載均衡
可見Zuul在路由轉發做了負載均衡。 如果不需要用 Ribbon 做負載均衡 可以指定服務實例的 Uri
zuul: routes: ribbonapi: path: /ribbonapi/** serviceid: hystric url: http://localhost:8089
重新啟動此時不會負載均衡,值會使用這個端口的進行服務!!! 如果你想指定 Url 並且想做負載均衡 那麽就需要自己維護負載均衡的服務註冊列表。 首先、ribbon.eureka.enabled 改為 false Ribbon 負載均衡客戶端不向Eureka Client 獲取服務註冊列表信息 然後需要自己維護一份註冊列表 該註冊列表對應的服務名為hiapi-vl(這 名字可自定義)
7.3.2、Zuul 上配置 API 接口的版本號
若要給每個服務的API接口的加上前綴 如:http://localhost:5000/v1/ribbonapi/hi 此時的v1就是版本號 待補充.....
7.3.3、Zuul 上配置熔斷器
Zuul 作為 Netflix 組件,可以和Ribbon、Eureka、Hystrix 等組件相結合, 實現負載均衡、熔斷器的功能。 在默認情況下, Zuul和Ribbon相結合,實現了負載均衡的功能 MyFallbackProvider.classpackage com.cr.eurekazuulclient.zull; import org.slf4j.LoggerFactory; import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider; 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; import java.util.logging.Logger; @Component public class MyFallbackProvider implements FallbackProvider { @Override public String getRoute() { // 表明是為哪個微服務提供回退,*表示為所有微服務提供回退 return "hystric"; } 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("The service is unavailable.".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } @Override public ClientHttpResponse fallbackResponse(String route, Throwable cause) { if (cause != null && cause.getCause() != null){ String reason = cause.getCause().getMessage(); System.out.println("exception:" + reason); } return fallbackResponse(); } }
此時啟動服務!!! 訪問hystrix的地址: 關閉該端口的服務: 此時的字符串是上文中的提示字符串
重啟hystrix服務:
7.3.4、在Zuul中使用過濾器
過濾器的類型:
實現過濾器自需要繼承ZuulFilter,並且實現其中的抽象方法 包括:filterType()、fil terOrder()、shouldFilter ()、Object run() filterType():過濾器類型 filterOrder()是過濾順序,值越小越早執行過濾器 shouldFilter()表示該過濾器是都過濾邏輯,為true則執行run()方法,false則不執行run()方法 run()方法寫具體的過濾邏輯 本次的測試請求參數是否傳送token參數 若沒有傳,則請求不被路由到具體的服務實例直接返回響應狀態嗎401
package com.cr.eurekazuulclient.zull; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.logging.Logger; @Component public class MyZuulFilter extends ZuulFilter { //private static Logger log= (Logger) LoggerFactory.getLogger(MyZuulFilter.class); @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); Object accessToken = request.getParameter("token"); if (accessToken == null){ System.out.println("token is empty"); //log.warning("token is empty"); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); try { ctx.getResponse().getWriter().write("token is empty"); }catch (Exception e){ return null; } } return null; } }
Zuul 的過濾器 ZuulFilter 的使用。 註意 EnableZuulProxy 註解能註冊到 eureka 服務上,是因為該註解包含了 eureka 客戶端的註解,該 EnableZuulProxy 是一個復合註解。 http://localhost:8150/routes 地址可以查看該zuul微服務網關代理了多少微服務的serviceId * 在 zuul 中定義了四種不同生命周期的過濾器類型: * * 1、pre:可以在請求被路由之前調用; * * 2、route:在路由請求時候被調用; * * 3、post:在route和error過濾器之後被調用; * * 4、error:處理請求時發生錯誤時被調用;
此時請求:
此時加上參數token:
MyZuulFilter這個 Bean 註入 IoC 容器之後 對請求進行了過濾 並在請求路由轉發之前進行了邏輯判斷 在實際開發中,可以用此過濾器進行安全驗證
7.3.5、Zuul常見的使用方式
Zuul 是采用了類似於 Spring MVC的DispatchServlet 來實現的 采用的是異步阻塞模型,所以性能比 Ngnix 差 由於 Zuul和其他 Netflix 組件可以相互配合、無縫集成 Zuul 很容易 就能實現負載均衡、智能路由和熔斷器等功能 大多數情況下、Zuul 都是以集群的形式存在的 由於Zuul的橫向擴展能力非常好 所以當負載過高時 可以通過添加實例來解決性能瓶頸。
7、Spring -Cloud-路由網管Spring Cloud Zuul