zuul设置熔断、断路器

在前面一篇文章中http://blog.csdn.net/tianyaleixiaowu/article/details/77884778,已经讲过了独立使用zuul进行反向代理了。在那篇文章中,没有使用eureka进行服务发现,而是使用简单的url配置,直接将用户请求发送到指定的url。这种做法适合于兼容一些老系统或者无法进行eureka服务注册的项目中,当时有一个东西没有提到,那就是熔断器。

我们将请求分发到多个微服务上,如果其中一个服务挂掉了,那么请求就会进行漫长的超时等待,最终会返回失败,甚至会影响整个服务链。我们需要一个熔断器来及时地处理挂掉的服务,及时响应给用户信息。

学过springcloud的都知道hystrix,可以在feign或者ribbon中使用它来进行熔断服务降级。zuul也有这样的功能ZuulFallbackProvider。

ZuulFallbackProvider提供了如果某微服务挂掉后,进入自定义处理逻辑的功能。但是需要注意的是,这个熔断器不支持以url配置的路由,必须要用serviceId的方式路由的方式才能使用熔断器。这样我们就要引入eureka服务中心了。

直接上代码。

创建eureka服务中心

项目eureka,pom.xml如下

<?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所在。

yml配置文件里设置一下端口,设置自己不作为eureka的client,免得把自己也作为一个客户端注册到eureka中。

server:
  port: 20000
spring:
  application:
    name: eureka
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false

然后就启动项目就OK了 访问localhost:20000,看到界面

配置zuul

可以参考文章开头提到的那篇zuul的文章,搭建基本骨架。在pom.xml添加eureka的依赖

<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,可以更精细地控制某个微服务挂掉后通过熔断的回调赋予默认值,然后用默认值来组合结果,来保证即便挂掉一个服务,其他的服务还能正常工作时的用户请求不会无响应。

注意:新版本,Springboot2.0以后,zuulFallbackProvider类没了,但是还可以使用FallbackProvider。特此通知

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据和云

从“挖光缆”到“剪网线”|蚂蚁金服异地多活的微服务体系

本文介绍了蚂蚁金服异地多活单元化架构的原理,以及微服务体系在此架构下的关键技术实现。

27640
来自专栏极客猴

阅读优秀代码是提升技术的最佳途径

在互联网行业,技术更新迭代太快了。我们身在行业中,要不断地学习提高自己的能力。有一种不错的方式来提高自己的技术实力。那就是阅读别人优秀的代码。

14730
来自专栏aoho求索

Spring Boot Actuator详解与深入应用(三):Prometheus+Grafana应用监控

本文系《Spring Boot Actuator详解与深入应用》中的第三篇。在前两篇文章,我们主要讲了Spring Boot Actuator 1.x与 2.x...

50630
来自专栏Debian社区

Java EE 8 最终规范现已正式推出

今日,我们发现 Java EE 在 其 GitHub 上的账号 发布了 Java EE 8 最终规范,并 提供了 PDF 格式的文件下载 。

9220
来自专栏Java进阶架构师

重磅消息:正式开源高性能异步Soul网关

24710
来自专栏yukong的小专栏

基于SpringCloud Finchley.SR1 、Spring Oauth2 SpringBoot 2.x、 vue、element-ui 微服务基础脚手架

github 地址 跪求大家star panda微服务工程地址 panda-admin前台工程地址

71630
来自专栏智能计算时代

「微服务架构」Google和eBay在构建微服务生态系统方面的深刻教训

当你看到来自谷歌,Twitter,eBay和亚马逊的大规模系统时,他们的架构已演变成类似的东西:一组多语言微服务。

22530
来自专栏圣杰的专栏

eShopOnContainers 知多少[4]:Catalog microservice

Catalog microservice(目录微服务)维护着所有产品信息,包括库存、价格。所以该微服务的核心业务为:

14430
来自专栏智能计算时代

「微服务架构」分散您的微服务组织

适应性 - 快速,轻松地进行变革的能力 - 已成为现代企业的首要目标,并迫使技术团队构建更容易,成本更低的平台。在这样的环境中工作,这些团队越来越多地被软件架构...

11140
来自专栏ImportSource

服务之美-读《微服务设计》笔记全集(一)

最近在微信读书上读《微服务设计》一书,目前读了30%多了,其间想法有点多,现分享给大家。

16820

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励