在前面一篇文章中http://blog.csdn.net/tianyaleixiaowu/article/details/77884778,已經講過了獨立使用zuul進行反向代理了。在那篇文章中,沒有使用eureka進行服務發現,而是使用簡單的url配置,直接將用戶請求發送到指定的url。這種作法適合於兼容一些老系統或者沒法進行eureka服務註冊的項目中,當時有一個東西沒有提到,那就是熔斷器。html
咱們將請求分發到多個微服務上,若是其中一個服務掛掉了,那麼請求就會進行漫長的超時等待,最終會返回失敗,甚至會影響整個服務鏈。咱們須要一個熔斷器來及時地處理掛掉的服務,及時響應給用戶信息。java
學過springcloud的都知道hystrix,能夠在feign或者ribbon中使用它來進行熔斷服務降級。zuul也有這樣的功能ZuulFallbackProvider。spring
ZuulFallbackProvider提供了若是某微服務掛掉後,進入自定義處理邏輯的功能。可是須要注意的是,這個熔斷器不支持以url配置的路由,必需要用serviceId的方式路由的方式才能使用熔斷器。這樣咱們就要引入eureka服務中心了。
apache
直接上代碼。json
項目eureka,pom.xml以下api
<?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.tianyalei</groupId> <artifactId>eureka</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>eureka</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR3</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
@SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }
在啓動類上加上EurekaServer表明這是eureka的server所在。app
yml配置文件裏設置一下端口,設置本身不做爲eureka的client,省得把本身也做爲一個客戶端註冊到eureka中。maven
server: port: 20000 spring: application: name: eureka eureka: instance: hostname: localhost client: register-with-eureka: false fetch-registry: false
而後就啓動項目就OK了
訪問localhost:20000,看到界面ide
能夠參考文章開頭提到的那篇zuul的文章,搭建基本骨架。在pom.xml添加eureka的依賴spring-boot
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
啓動類也修改一下註解
@EnableZuulProxy @SpringCloudApplication public class TestzuulApplication { public static void main(String[] args) { SpringApplication.run(TestzuulApplication.class, args); } }
yml配置文件裏配置一下Application.name,routes,和eureka的註冊地址。
spring: application: name: zuul server: port: 9000 zuul: routes: api-2: path: /user/** #url: http://localhost:9001/ serviceId: user eureka: client: service-url: defaultZone: http://localhost:20000/eureka/
注意routes裏原來是用url指定的,這裏用serviceId,serviceId就是微服務在eureka上註冊的名字,對應spring.application.name。
我這裏添加映射/user/**的請求會被分發到user服務中,等會建立個user服務。
下面是關鍵部分,設置熔斷器。
package com.tianyalei.testzuul.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; import java.nio.charset.Charset; @Component public class UserServiceFallbackProvider implements ZuulFallbackProvider { @Override public String getRoute() { return "user"; } @Override public ClientHttpResponse fallbackResponse() { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return this.getStatusCode().value(); } @Override public String getStatusText() throws IOException { return this.getStatusCode().getReasonPhrase(); } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("Service-user不可用".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8")); headers.setContentType(mt); return headers; } }; } }
getRoute方法的返回值就是要監聽的掛掉的微服務名字,這裏只能是serviceId,不能是url,指定爲「user」,那麼在user服務不存在時,就會去執行後面代碼的邏輯,設置Code,body什麼的自定義內容返回給調用者。
其實到這裏就能夠測試熔斷效果了,由於咱們並無serviceId爲「user」的服務。因此就會進入到熔斷邏輯裏了。
啓動zuul項目。
能夠看到zuul已經註冊到eureka上了,而後咱們訪問zuul/user,讓它轉發到user服務試試。
能夠看到已經進入到熔斷後的自定義處理了,目的已經達成。
下面咱們試試user服務正常時的狀況。
一樣是建立一個Springboot項目,加入eureka依賴,配置yml
spring: application: name: user server: port: 9001 eureka: client: service-url: defaultZone: http://localhost:20000/eureka/
@SpringBootApplication @EnableEurekaClient public class ZuuluserApplication { public static void main(String[] args) { SpringApplication.run(ZuuluserApplication.class, args); } }
定義個Controller
@RestController public class UserController { @RequestMapping("") public Object user() { return "from user"; } }
啓動user項目,等待eureka發現user服務,有必定的延時才能發現。再次訪問localhost:9000/user。
能夠看到正常進入到user服務了,固然能夠屢次嘗試啓停user服務,看看熔斷器的工做狀況。
總結:
能夠看到zuul的熔斷器主要目的和意義在於針對某個微服務的異常狀態進行控制,並不能具體的針對某個具體的請求方法進行控制,譬如個人請求須要關聯商品、用戶、訂單三個微服務,須要三個服務的返回值組合成一個結果返回給用戶,那麼這個熔斷器就不能作出合適的處理了。固然了,須要關聯多個微服務的請求,咱們是採用feign來完成。feign裏也自帶的有hystrix,能夠更精細地控制某個微服務掛掉後經過熔斷的回調賦予默認值,而後用默認值來組合結果,來保證即使掛掉一個服務,其餘的服務還能正常工做時的用戶請求不會無響應。
參考:https://blog.csdn.net/tianyaleixiaowu/article/details/78064127