在前面一篇文章中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