SpringCloud 学习笔记4


Hystrix

简介

Hystix,即熔断器。主页:https://github.com/Netflix/Hystrix/ , 已经停更两年多了。

20200819141026


Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。

20200819141119


熔断器的工作机制

20200819141728


正常工作的情况下,客户端请求调用服务API接口:

20200819141817


当有服务出现异常时,直接进行失败回滚,服务降级处理:

20200819141853


当服务繁忙时,如果服务出现异常,不是粗暴的直接报错,而是返回一个友好的提示,虽然拒绝了用户的访问,但是会返回一个结果。

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

系统特别繁忙时,一些次要服务暂时中断,优先保证主要服务的畅通,一切资源优先让给主要服务来使用,在双十一、618时,京东天猫都会采用这样的策略。


动手实践

改造服务消费者

引入依赖

首先在服务消费者 ConsumerDemo 中引入Hystix依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.0.1.RELEASE</version>
</dependency>

开启熔断

ConsumerDemo 的启动类上面,添加 @EnableCircuitBreaker 注释,开启熔断:

@EnableCircuitBreaker
@SpringBootApplication
@EnableDiscoveryClient // 开启Eureka客户端
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

也可以使用 @SpringCloudApplication 注解,来代替 @EnableCircuitBreaker@SpringBootApplication@EnableDiscoveryClient 注解,下面是 `` 注解的源码:

20200820101603


编写降级逻辑

当目标服务的调用出现故障,我们需要快速解决,给用户一个友好提示。因此需要提前编写好,失败时的降级处理逻辑,要使用 @HystixCommond 注解来完成。

改造 ConsumerController ,在用来访问的 User 服务的方法中声明一个失败时的回滚处理函数:

@RestController
@RequestMapping(value = "consumer")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    private static final Logger logger = LoggerFactory.getLogger(ConsumerController.class);
    
    @HystrixCommand(fallbackMethod = "queryByIdFallback")
    @GetMapping("{id}")
    public String queryById(@PathVariable(value = "id") Long id) {
        String url = "http://user-service/user/" + id;
        User user = restTemplate.getForObject(url, User.class);
        assert user != null;
        return user.toString();
    }

    public String queryByIdFallback(Long id) {
        logger.error("查询用户信息失败,id: {}", id);
        return "不好意思,服务器正忙!";
    }
}

注意:因为熔断的降级逻辑方法必须和正常逻辑方法的有相同的参数列表和返回值声明。如这里的熔断降级逻辑方法和政策逻辑方法的参数列表都只有一个 Long 类型的数据,返回值都是 String 类型的数据。


说明:

  • @HystrixCommand :该注释用于指定一些方法,这些方法作为 hystrix 命令进行处理。
  • fallbackMethod :该成员变量用于指定一个降级逻辑的方法。
  • 超时时间默认是1000毫秒。

改造服务提供者

改造服务提供者,随机休眠一段时间,以触发熔断:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id) {
        // 为了演示超时现象,我们在这里然线程休眠,时间随机 0~2000毫秒
        try {
            Thread.sleep(new Random().nextInt(2000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return userMapper.selectByPrimaryKey(id);
    }
}

启动测试

启动 EurekaServer(注册服务)、UserService、ConsumerDemo,通过服务消费者 ConsumerDemo 调用服务提供者 UserService,UserService 提供的服务随机休眠0-2000毫秒:

20200820113136


调用服务:

20200820112536


查询失败:

20200820113509


查询成功:

20200820113400


优化

虽然熔断实现了,但是我们的重试机制似乎没有生效,是这样吗?

其实这里是因为我们的Ribbon超时时间设置的是1000ms:

20200820132357


而Hystix的超时时间默认也是1000ms,因此重试机制没有被触发,而是先触发了熔断。

所以,Ribbon的超时时间一定要小于Hystix的超时时间。

我们可以通过hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds来设置Hystrix超时时间。

配置文件中设置:

hystrix:
  command:
  	default:
        execution:
          isolation:
            thread:
              timeoutInMillisecond: 6000 # 设置hystrix的超时时间为6000ms

方法中的设置:

@HystrixCommand(commandProperties = 
    @HystrixProperty(
                name = "hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds", 
                value = "6000")
)
@GetMapping("{id}")
public String queryById(@PathVariable(value = "id") Long id) {
    String url = "http://user-service/user/" + id;
    User user = restTemplate.getForObject(url, User.class);
    assert user != null;
    return user.toString();
}

在编写降级逻辑的时候,我们也可以使用 @DefaultProperties 注解,来指定降级逻辑的方法,该注解和 @HystrixCommand 注解不同,@DefaultProperties 注解在类上使用,类中所有的方法都可以开启剪辑逻辑(用@HystrixCommand 注解开启),@HystrixCommand 注解在方法上使用,只能是对应的某个方法使用降级逻辑:

@DefaultProperties(fallbackMethod = "defaultFallback")
@RestController
@RequestMapping(value = "consumer")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    private static final Logger logger = LoggerFactory.getLogger(ConsumerController.class);
    
    @HystrixCommand					// 该方法开启降级逻辑
    @GetMapping("{id}")
    public String queryById(@PathVariable(value = "id") Long id) {
        String url = "http://user-service/user/" + id;
        User user = restTemplate.getForObject(url, User.class);
        assert user != null;
        return user.toString();
    }

    public String defaultFallback() {
        return "不好意思,服务器正忙!";
    }
}

熔断服务

熔断原理

熔断器也叫断路器,其英文名为 Circuit Breaker

20200820140332


状态机有三个状态:

  • Closed:关闭状态(断路器关闭),所有请求都正常访问。
  • Open:打开状态(断路器打开),所有请求都会被降级。Hystrix 会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,默认失败比例的阈值是 50% ,请求次数最少不低于20次。
  • Half Open:半开状态,Closed 状态不是永久的,关闭后会进入休眠时间(默认是5秒),随后熔断器后自动进入半开状态。此时释放部分请求通过,若这些请求都是健康的,则会完全打开断路器,否则继续保持关闭,再次进入休眠计时。

动手实践

为了能够精准的控制请求的成功或失败,服务消费者的调用业务中添加一段逻辑:

在 ConsumerDemo 例子中:

@RestController
@RequestMapping(value = "consumer")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    private static final Logger logger = LoggerFactory.getLogger(ConsumerController.class);

    @HystrixCommand(
            commandProperties = {
                    @HystrixProperty(
                            // 熔断器请求阈值次数 10 次。
                            name = "circuitBreaker.requestVolumeThreshold",
                            value = "10"
                    ),
                    @HystrixProperty(
                            // 熔断器关闭状态时,休眠计时时间(毫秒为单位)。
                            name = "circuitBreaker.sleepWindowInMilliseconds",
                            value = "10000"
                    ),
                    @HystrixProperty(
                            // 失败请求百分比,单失败请求百分比达到60%时,熔断器打开。
                            name = "circuitBreaker.errorThresholdPercentage",
                            value = "60"
                    )
            },
            fallbackMethod = "queryByIdFallback"
    )
    @GetMapping("{id}")
    public String queryById(@PathVariable(value = "id") Long id) {
        /* 这个方法中可以添加一些逻辑,来判断访问 */
        // 例如,随便写个逻辑
        // if (id == 1) {
        //     throw new RuntimeException("不好意思,服务器正忙!")
        // }
        String url = "http://user-service/user/" + id;
        User user = restTemplate.getForObject(url, User.class);
        assert user != null;
        return user.toString();
    }

    public String queryByIdFallback(Long id) {
        logger.error("查询用户信息失败,id: {}", id);
        return "不好意思,服务器正忙!";
    }
}

说明:

  1. commandProperties 参数:对于注解 @HystrixCommand 中指定的方法,配置一些数据。
  2. @HystrixProperty 注解:指定要被修改的变量。
  3. requestVolumeThreshold : 触发熔断的最小次数(默认是20次)
  4. sleepWindowInMilliseconds : 触发熔断的失败请求最小占比(默认为 50%)
  5. errorThresholdPercentage : 休眠时常(默认是 5000 毫秒)

这样,如果参数 id 为 1,一定失败,其他情况可能会成功,也可能会跳转到失败逻辑方法中。

当我们疯狂访问 id = 1 的请求时,超过我们设定的请求阈值次数 10 次,就会触发熔断。断路器开启,一切请求都会被降级处理。此时如果访问 id != 1 的请求,会发现返回的也是失败,而且失败时间相对于正常访问出错的时间短的很多倍。


原文地址:https://www.cnblogs.com/liyihua/p/14482630.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Nacos 中的参数有很多,如:命名空间、分组名、服务名、保护阈值、服务路由类型、临时实例等,那这些参数都是什么意思?又该如何设置?接下来我们一起来盘它。 1.命名空间 在 Nacos 中通过命名空间(Namespace)+ 分组(Group)+服务名(Name)可以定位到一个唯一的服务实例。 命名
Nacos 支持两种 HTTP 服务请求,一个是 REST Template,另一个是 Feign Client。之前的文章咱们介绍过 Rest Template 的调用方式,主要是通过 Ribbon(负载均衡) + RestTemplate 实现 HTTP 服务调用的,请求的核心代码是这样的: @
Nacos 是 Spring Cloud Alibaba 中一个重要的组成部分,它提供了两个重要的功能:服务注册与发现和统一的配置中心功能。 服务注册与发现功能解决了微服务集群中,调用者和服务提供者连接管理和请求转发的功能,让程序的开发者无需过多的关注服务提供者的稳定性和健康程度以及调用地址,因为这
Spring Cloud Alibaba 是阿里巴巴提供的一站式微服务开发解决方案,目前已被 Spring Cloud 官方收录。而 Nacos 作为 Spring Cloud Alibaba 的核心组件之一,提供了两个非常重要的功能:服务注册中心(服务注册和发现)功能,和统一配置中心功能。 Nac
在 Nacos 的路由策略中有 3 个比较重要的内容:权重、保护阈值和就近访问。因为这 3 个内容都是彼此独立的,所以今天我们就单独拎出“保护阈值”来详细聊聊。 保护阈值 保护阈值(ProtectThreshold):为了防止因过多实例故障,导致所有流量全部流入剩余健康实例,继而造成流量压力将剩余健
前两天遇到了一个问题,Nacos 中的永久服务删除不了,折腾了一番,最后还是顺利解决了。以下是原因分析和解决方案,建议先收藏,以备不时之需。 临时实例和持久化实例是 Nacos 1.0.0 中新增了一个特性。临时实例和持久化实例最大的区别是健康检查的方式:临时实例使用客户端主动上报的健康检查模式,而
Spring Cloud Alibaba 技术体系中的 Nacos,提供了两个重要的功能:注册中心(服务注册与发现)功能和配置中心功能。 其中注册中心解决了微服务调用中,服务提供者和服务调用者的解耦,让程序开发者可以无需过多的关注服务提供者和调用者的运行细节,只需要通过 Nacos 的注册中心就可以
负载均衡通器常有两种实现手段,一种是服务端负载均衡器,另一种是客户端负载均衡器,而我们今天的主角 Ribbon 就属于后者——客户端负载均衡器。 服务端负载均衡器的问题是,它提供了更强的流量控制权,但无法满足不同的消费者希望使用不同负载均衡策略的需求,而使用不同负载均衡策略的场景确实是存在的,所以客
本篇文章为大家展示了如何解决Spring Cloud 服务冲突问题,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、背景...
本篇内容主要讲解“spring cloud服务的注册与发现怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“spri...
本篇内容介绍了“Dubbo怎么实现Spring Cloud服务治理 ”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
本篇内容主要讲解“SpringCloud相关面试题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringCloud相...
如何分析Spring Cloud Ribbon、Spring Cloud Feign以及断路器,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希
这篇文章主要讲解了“springcloud微服务的组成部分有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“s...
这篇文章主要讲解了“SpringCloud的OpenFeign项目怎么创建”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习...
本篇内容主要讲解“spring cloud oauth3整合JWT后获取用户信息不全怎么办”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带...
怎样解析微服务架构SpringCloud,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。...
这篇文章主要介绍spring cloud中API网关的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、服务网关简介1、外观模式客户端...
本篇内容介绍了“Spring Cloud微服务的相关问题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
本文小编为大家详细介绍“spring cloud config整合gitlab如何搭建分布式的配置中心”,内容详细,步骤清晰,细节处理妥当,希望这篇“spring cloud config整合gi...