SpringCloud(五)—Hystrix断路器

分布式系统面临的问题

分布式架构和微服务架构中,都有很多的应用模块,每个模块之间都会有相互依赖的关系,如果中间有一个模块出现了问题,很可能会影响到整个系统的运行。

服务雪崩

扇出: 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的 扇出。

雪崩效应: 如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,这就是 雪崩效应。

服务雪崩效应: 在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为 服务雪崩效应。服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。

下面我们通过结构图了解一下什么是灾难性的服务雪崩效应?

正常情况下:

在这里插入图片描述

当某种请过增多,造成了服务T的故障时:

在这里插入图片描述

会导致服务U故障,继续拓展为:

在这里插入图片描述

最终导致整个服务的不可用:

在这里插入图片描述

这就是所谓的灾难性雪崩!

造成雪崩的原因有3种:

  1. 服务提供者不可用(硬件故障,程序Bug,缓存击穿,用户大量请求)
  2. 重试加大流量(用户重试,代码逻辑重试)
  3. 服务调用者不可用(同步等待造成的资源耗尽)

什么是Hystrix

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

断路器 本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

Hystrix服务降级

生活中的服务降级:

比如你去超市买鱼,平常超市买鱼会额外赠送杀鱼的服务。等到逢年过节,超时繁忙时,可能就不提供杀鱼服务了,这就是服务的降级。

在开发中的服务降级:

可以简单理解为:用户访问系统的服务,如果服务出现异常,不是粗暴的直接报错,返回给用户404或者500,而是返回一个友好的提示,虽然拒绝了用户的访问,但是会返回一个结果。

代码实现

0)准备测试环境

在 producer 项目中新增一个方法 getById

@RequestMapping("getById")
public User getById(Integer id) {
    // 模拟请求过程中出错
    if (id == 0) {
        int a = 1/0;
    }
    return userService.getUserById(id);
}

在 consumer 项目中添加调用此方法的控制器

@RequestMapping("getById")
public User getById(Integer id) {
    return userClient.getById(id);
}

UserClient.java

@RequestMapping("/getById")
User getById(@RequestParam Integer id);

访问接口,测试结果如下

在这里插入图片描述

在这里插入图片描述

可以看出,如果访问过程中出现了错误,那么错误将会直接暴露给用户

1)引入依赖

<!-- 服务熔断组件 Hystrix -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2)修改controller

@RequestMapping("getById")
@HystrixCommand(fallbackMethod = "fallBack_getById")
public User getById(Integer id) {
    return userClient.getById(id);
}

// 降级的方法
public User fallBack_getById(Integer id) {
    User user = new User();
    user.setId(0);
    user.setName("该ID: " + id + "没有对应的信息");
    user.setPassword("password");
    user.setInfo("测试信息...");
    return user;
}

3)修改启动类

修改 consumer 中启动类,添加 @EnableCircuitBreaker

@SpringBootApplication
@EnableEurekaClient // 开启EurekaClient功能
@EnableFeignClients // 开启Feign的功能
@EnableCircuitBreaker   // 开启hystrix对熔断机制的支持
public class SpringCloud01Consumer {
    public static void main(String[] args) {
        System.out.println("消费者服务启动...8080");
        SpringApplication.run(SpringCloud01Consumer.class, args);
    }
}

4)熔断测试

再次访问 http://localhost:8080/getById?id=0 ,可以看出,已经不再是 500 错误信息,而是给用户一个友好的提示

在这里插入图片描述

服务降级优化-彻底解耦

上面的方式很显然对开发人员来说并不友好,controller层怎么可以写其他的方法呢?受不了!

接下来介绍一种 解耦的方法

代码实现

consumer项目

1)controller恢复之前的代码

@RestController
public class UserController {
    @Autowired
    private UserClient userClient;

    @RequestMapping("queryUserList")
    public List queryUserList() {
        return userClient.queryUserList();
    }

    @RequestMapping("getById")
    public User getById(Integer id) {
        return userClient.getById(id);
    }
}

2)创建专门存放降级方法的类

// fallbackFactory 熔断机制对应方法的工厂
@Component
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable throwable) {
        return new UserClient() {
            @Override
            public List<User> queryUserList() {
                return null;
            }

            @Override
            public User getById(Integer id) {
                User user = new User();
                user.setId(0);
                user.setName("该ID: " + id + "没有对应的信息");
                user.setPassword("password");
                user.setInfo("测试信息...解耦的方式进行配置...");
                return user;
            }
        };
    }
}

3)修改UserClient,添加注解属性

// 指定 fallbackFactory = UserClientFallbackFactory.class
@FeignClient(value = "springcloud-producer", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {

    @RequestMapping("/list")
    List<User> queryUserList();

    @RequestMapping("/getById")
    User getById(@RequestParam Integer id);
}

4)开启配置

# 开启服务熔断策略
feign.hystrix.enabled=true

测试

访问:http://localhost:8080/getById?id=0

在这里插入图片描述

服务熔断

熔断其实是在降级的基础上引入了重试的机制。当某个时间内失败的次数达到了一定次数就会触发熔断机制。熔断机制是应对雪崩效应的一种微服务链路保护机制。

在这里插入图片描述

断路器很好理解,当Hystrix Command请求后端服务熔断器在10秒内发现请求总数超过20,并且错误百分比超过50%,,断路器会切换到开路状态(Open)。这时所有请求会直接失败而不会发送到后端服务。 断路器保持在开路状态一段时间后(默认5秒),自动切换到半开路状态(HALF-OPEN)。这时会判断下一次请求的返回情况, 如果请求成功,断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN)。 Hystrix的断路器就像我们家庭电路中的保险丝,一旦后端服务不可用,断路器会直接切断请求链,避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。

那么当断路器打开之后会发生什么呢?当熔断器在10秒内发现请求总数超过20,并且错误百分比超过50%,这个时候熔断器打开。打开之后,再有请求调用的时候,将不会调用主逻辑,而是直接调用降级逻辑,返回fallback。通过断路器,实现了自动地发现错误并将主逻辑切换为降级逻辑,减少响应延迟的效果。

在断路器打开之后,处理逻辑并没有结束,我们的降级逻辑已经被成了主逻辑,那么原来的主逻辑要如何恢复呢?对于这一问题,hystrix也为我们实现了自动恢复功能。当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。

通过上面的一系列机制,hystrix的断路器实现了对依赖资源故障的端口、对降级策略的自动切换以及对主逻辑的自动恢复机制。这使得我们的微服务在依赖外部服务或资源的时候得到了非常好的保护,同时对于一些具备降级逻辑的业务需求可以实现自动化的切换与恢复,相比于设置开关由监控和运维来进行切换的传统实现方式显得更为智能和高效。

可通过注解来自定义配置

@HystrixCommand(fallbackMethod = "purchaseTicketFallBack", commandProperties = {
    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),   // 滑动窗口大小
    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),   // 过多久再次检测是否开启熔断器
    @HystrixProperty(name ="circuitBreaker.errorThresholdPercentage",value = "50")  // 错误率

})

Hystrix可视化数据监控 dashboard

什么是 dashboard

Hystrix-dashboard 是一款针对 Hystrix 进行准实时监控的工具,通过 Hystrix Dashboard 我们可以在直观地看到各 Hystrix Command 的请求响应时间, 请求成功率等数据。Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。

代码实现

1)引入依赖

<!-- actuator -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- hystrix和 hystrix-dashboard相关 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

2)配置启动类

在启动的配置类中添加注解 @EnableHystrixDashboard // 开启dashboard仪表盘

3)注册 HystrixMetricsStreamServlet

/**
 * 配置Hystrix.stream的servlet
 */
@Bean
public ServletRegistrationBean registrationBean() {
    HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
    registrationBean.setLoadOnStartup(1);
    registrationBean.addUrlMappings("/hystrix.stream");
    registrationBean.setName("HystrixMetricsStreamServlet");
    return registrationBean;
}

4)启动项目,进行测试

在这里插入图片描述
先访问自己的服务,比如:http://localhost:8080/getById?id=1 , http://localhost:8080/queryUserList

再访问:http://localhost:8080/hystrix/

在这里插入图片描述

进入监控页面

在这里插入图片描述

如何查看

  • 一个绿色的实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。

  • 一条曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。

  • 面板每个指标所代表的的意义:

在这里插入图片描述

小结

  1. Hystrix服务降级,一般开发中不使用
  2. Hystrix可视化数据监控 dashboard,一般是运维人员来使用的,监控服务的信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值