Spring Cloud Netflix Hystrix

得意时要看淡,失意时要看开。不论得意失意,切莫大意;不论成功失败,切莫止步。志得意满时,需要的是淡然,给自己留一条退路;失意落魄时,需要的是泰然,给自己觅一条出路Spring Cloud Netflix Hystrix,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

Hystrix简介

在微服务架构中,各个服务独立部署且服务与服务之前存在相互依赖关系。与单块系统相比,微服务架构中出现服务访问失败的原因和场景非常复杂,需要我们从服务可靠性的角度出发对服务本身以及服务与服务之间的交互过程进行设计。服务可靠性是微服务架构的关键要素之一。

服务可靠性问题同时涉及服务的提供者和消费者 对于服务提供者而言,要做的事情比简单,一旦自身服务发生错误,那么应该快速返回合理的处理结果,也就是要做到快速反馈。而对于服务消费者而言, 事情就比较复杂了,一方面可以采用超时( Timeout)
和重试( Retry 常见方法),另一方面也有一些模式对服务提供者发生失败的场景。
在这里插入图片描述
负载均衡是提高系统的性能,而服务熔断是提高服务消费者的容错机制则防止服务故障而导致的系统问题。这些机制包括服务隔离,服务熔断,服务回退,服务限流

  • 服务熔断

熔断这一概念来源于电子工程中的熔断器。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游为了保护系统整体的可用性,可以暂时切断对下游服务的调用,这种牺牲局部,保全对整体的措施叫做熔断。

在这里插入图片描述

  • 服务降级

服务降级,就是当某个服务熔断后,服务器将不再被调用,此时客户端可以自己准备一个本地的Fallback回调,返回一些数据。

  • 服务限流

服务限流就是限制系统的输入和输出的流量达到保护系统的目的。一般来说系统的吞吐量是可以被预测的,为了保护系统的稳定运行,一旦达到需要限流的阙值,就需要限流量并采用少量的措施完成限制流量的目的。

  • 服务隔离

服务隔离是将系统按照一定原则划分为若干模块,各个模块之间相对对立,无强依赖。当有故障发生时,能将问题隔离在某个模块内部,不扩散风险不影响整体的系统服务。

  • 服务回退

服务回退是在处理服务依赖而导致的异常时也是一种有效的容错机制。当远程调用发生异常时,服务回退不是直接抛出异常,而是产生另外的机制来应对异常,相当于执行了另一条路上的代码而返回的处理结果。

Hystrix组件对Web Service的支持

对RestTemplate的支持

  1. 引入hystrix的依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
  1. @EnableHystrix启动类激活Hystrix

在这里插入图片描述
@EnableCircuitBreaker在3.0.1版本中已经移除了,2点多版本显示过时。改用@EnableHystrix实现了前者全部功能。

@SpringBootApplication
@EnableDiscoveryClient
//hystrix熔断处理
//@EnableCircuitBreaker  已过时
@EnableHystrix

public class ProviderServiceApplication {

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

}
  1. 配置熔断触发的降级逻辑
    /**
     * 服务降级策略,要求参数和返回值一致
     */
    BillMessage default_billMessage(Integer id){
        BillMessage billMessage = new BillMessage();
        billMessage.setStatus(500);
        billMessage.setMessage("服务器繁忙,请稍后再试!");
        billMessage.setBill(null);
        return billMessage;
    }

//降级处理当服务未响应时配置本地的返回数据
  1. @HystrixCommand注解声明接口保护
//声明式熔断保护,参数配置降级策略
@HystrixCommand(fallbackMethod = "default_billMessage")
@GetMapping(value = "/hystrix/{id}")
BillMessage method1(@Autowired RestTemplate restTemplate, @PathVariable("id") Integer id){
    BillMessage forObject = restTemplate.getForObject("http://localhost:8081/bill/" + id, BillMessage.class);
    return forObject;
}

各个模块完整代码

controller

@RestController
@RequestMapping(value = "/provider")


public class ProviderController {
    @Autowired
    ProviderService providerService;

    @Autowired RestTemplate restTemplate;

    @GetMapping(value = "/{id}")
    ProviderMessage getById(@PathVariable int id){
        ProviderMessage byId = providerService.getById(id);
        return byId;
    }


    //声明式熔断保护,参数配置降级策略
    @HystrixCommand(fallbackMethod = "default_billMessage")
    @GetMapping(value = "/hystrix/{id}")
    BillMessage method1(@PathVariable("id") Integer id){
        BillMessage forObject = restTemplate.getForObject("http://localhost:8081/bill/" + id, BillMessage.class);
        return forObject;
    }

	/**
     * 服务降级策略,要求参数和返回值一致
     */
    BillMessage default_billMessage(Integer id){
        BillMessage billMessage = new BillMessage();
        billMessage.setStatus(500);
        billMessage.setMessage("服务器繁忙,请稍后再试!");
        billMessage.setBill(null);
        return billMessage;
    }
}

feignclient

@FeignClient(name = "bill-service")
public interface BillClient {
    @GetMapping(value = "/bill/{id}")
    BillMessage method1(@PathVariable("id") Integer id);
}

启动服务:
在这里插入图片描述
服务之间的调用关系
在这里插入图片描述
启动熔断处理后访问接口:
在这里插入图片描述
关闭BillService服务模拟服务未响应的错误,再次访问接口:

在这里插入图片描述

在这里插入图片描述
返回本地数据数据熔断处理及服务降级生效。

如果所有接口的返回值类型是一样的就可以配置公共的降级处理方法@DefaultProperties参数配置为某个方法时,无需在单个接口处再次配置方法。

对Feign的支持

  1. feign组件的配置及启动

Spring Cloud Netflix Feign配置配置完成后访问接口:

/**
 * feign代理api接口
 *
 */
@Autowired private BillClient billClient;

@GetMapping(value = "/feign/{id}")
BillMessage method2(@PathVariable("id") Integer id){
    BillMessage billMessage = billClient.method1(id);
    return billMessage;
}

在这里插入图片描述

先配置feign的代理,不懂得可以看我之前的文章。成功访问。

  1. 配置hystrix组件
  • 导入依赖
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
     <version>2.2.2.RELEASE</version>
 </dependency>
  • 配置文件开启feign对hystrix的支持
feign.hystrix.enabled=true
  • feign代理的实现类作为降级方法

在这里插入图片描述

@FeignClient(name = "bill-service", fallback = BillClientImpl.class)
public interface BillClient {
    @GetMapping(value = "/bill/{id}")
    BillMessage method1(@PathVariable("id") Integer id);
}
public class BillClientImpl implements BillClient {
    @Override
    public BillMessage method1(Integer id) {
        BillMessage billMessage = new BillMessage();
        billMessage.setBill(null);
        billMessage.setMessage("feign配置hystrix返回服务器繁忙!");
        billMessage.setStatus(500);
        return billMessage;
    }
}
  1. 启动类配置hystrix的启动注解@EnableHystrix
@SpringBootApplication
@EnableDiscoveryClient
//hystrix熔断处理
//@EnableCircuitBreaker  已过时
@EnableHystrix

//feign的配置
@EnableFeignClients
public class ProviderServiceApplication {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

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

}

启动服务

在这里插入图片描述
访问消费者接口
在这里插入图片描述
停掉hystrix管理的服务模拟服务繁忙
在这里插入图片描述

启动后通过访问hystrix管理的feign接口发现返回500的错误,查了原因后发现是hystrix未生效

解决配置了feign.hystrix.enabled:=true不生效的原因

原因是:feign.hystrix.enabled=true是springcloud2020以前的版本,而之后的版本是:feign.circuitbreaker.enabled=true

修改配置后重启服务,访问hystrix管理的接口:

在这里插入图片描述

hystrix服务熔断及降级处理的方式,使用feign和RestTemplate的区别主要在服务降级:

    //声明式熔断保护,参数配置降级策略
    @HystrixCommand(fallbackMethod = "default_billMessage")
    @GetMapping(value = "/hystrix/{id}")
    BillMessage method1(@PathVariable("id") Integer id){
        BillMessage forObject = restTemplate.getForObject("http://localhost:8081/bill/" + id, BillMessage.class);
        return forObject;
    }
    /**
     * 服务降级策略,要求参数和返回值一致
     */
    BillMessage default_billMessage(Integer id){
        BillMessage billMessage = new BillMessage();
        billMessage.setStatus(500);
        billMessage.setMessage("服务器繁忙,请稍后再试!");
        billMessage.setBill(null);
        return billMessage;
    }

RestTemplate服务降级在controller层定义降级方法,并通过熔断保护注解的fallbackMethod参数配置

feign代理的是通过feign代理接口的接口实现类作为降级方法:

在这里插入图片描述

@FeignClient(name = "bill-service", fallback = BillClientImpl.class)
public interface BillClient {
    @GetMapping(value = "/bill/{id}")
    BillMessage method1(@PathVariable("id") Integer id);
}
@Component
public class BillClientImpl implements BillClient {
    @Override
    public BillMessage method1(Integer id) {
        BillMessage billMessage = new BillMessage();
        billMessage.setBill(null);
        billMessage.setMessage("feign配置hystrix返回服务器繁忙!");
        billMessage.setStatus(500);
        return billMessage;
    }
}

接口实现类要注入到spring 容器中,并在父接口中通过fallback参数声明降级方法类

两种实现方法的完整代码如下,包括controller层可feign代理接口:

controller

@RestController
@RequestMapping(value = "/provider")


public class ProviderController {
    @Autowired
    ProviderService providerService;

    @Autowired RestTemplate restTemplate;

    @GetMapping(value = "/{id}")
    ProviderMessage getById(@PathVariable int id){
        ProviderMessage byId = providerService.getById(id);
        return byId;
    }


    //声明式熔断保护,参数配置降级策略
    @HystrixCommand(fallbackMethod = "default_billMessage")
    @GetMapping(value = "/hystrix/{id}")
    BillMessage method1(@PathVariable("id") Integer id){
        BillMessage forObject = restTemplate.getForObject("http://localhost:8081/bill/" + id, BillMessage.class);
        return forObject;
    }
    /**
     * 服务降级策略,要求参数和返回值一致
     */
    BillMessage default_billMessage(Integer id){
        BillMessage billMessage = new BillMessage();
        billMessage.setStatus(500);
        billMessage.setMessage("服务器繁忙,请稍后再试!");
        billMessage.setBill(null);
        return billMessage;
    }


    /**
     * feign代理api接口
     *
     */

    @Resource
    private BillClient billClient;

    @HystrixCommand
    @GetMapping(value = "/feign/{id}")
    BillMessage method2(@PathVariable("id") Integer id){
        BillMessage billMessage = billClient.method1(id);
        return billMessage;
    }

}

feignclient

@FeignClient(name = "bill-service", fallback = BillClientImpl.class)
public interface BillClient {
    @GetMapping(value = "/bill/{id}")
    BillMessage method1(@PathVariable("id") Integer id);
}


feignclientimpl


@Component
public class BillClientImpl implements BillClient {
    @Override
    public BillMessage method1(Integer id) {
        BillMessage billMessage = new BillMessage();
        billMessage.setBill(null);
        billMessage.setMessage("feign配置hystrix返回服务器繁忙!");
        billMessage.setStatus(500);
        return billMessage;
    }
}

总结

使用feign作为服务调用端对hystrix的整合分四个步骤:

  • 引入hystrix依赖:
<dependency>
   <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>
  • feign开启对hystrix的支持
feign.circuitbreaker.enabled=true
  • 定义fein代理接口的实现类作为服务降级触发的降级逻辑,并在接口注解使用fallback声明该类
//接口
@FeignClient(name = "bill-service", fallback = BillClientImpl.class)


//实现类
/*
实现类要注入到spring容器中
*/
@Component
public class BillClientImpl implements BillClient {
    @Override
    public BillMessage method1(Integer id) {
        BillMessage billMessage = new BillMessage();
        billMessage.setBill(null);
        billMessage.setMessage("feign配置hystrix返回服务器繁忙!");
        billMessage.setStatus(500);
        return billMessage;
    }
}

  • 接口开启hystrix熔断保护@HystrixCommand
    @HystrixCommand
    @GetMapping(value = "/feign/{id}")
    BillMessage method2(@PathVariable("id") Integer id){
        BillMessage billMessage = billClient.method1(id);
        return billMessage;
    }

Hystrix监控平台

除了实现容错功能外,Hystrix还提供了近乎实时的监控HystrixCommand和HystrixObservableCommand在执行时会生成执行结果和运行指标。这些状态会暴露在Actuator提供的health端点中。只需为项目添加spring-boot-actuator依赖重启项目即可,访问地址http://localhost:9000/actuator/hystrix.stream可看到监控数据(端口是启用hystrix熔断保护的端口)。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在这里插入图片描述

发现未找到hystrix服务,查看actuator暴露的接口:

在这里插入图片描述
需要通过配置暴露接口:

management.endpoints.web.exposure.include=*

重启项目,会一直ping回去hystrix熔断保护信息:

在这里插入图片描述
这时只要访问一个由hystrix熔断保护的接口,监控系统就会返回该接口的监控信息:

在这里插入图片描述

在这里插入图片描述
可以看到上面文本式的监控信息很不直观,spring cloud提供了DashBoard的图像化监控。Hystrix仪表盘可以显示每个熔断保护的接口及注解了@HystrixCommand的接口。

要使用hystrix仪表盘还需要再导入一个依赖:

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

再启动类上添加@EnableHystrixDashboard

在这里插入图片描述
重启服务,输入http://localhost:8082/hystrix端口是开启熔断保护的端口。

在这里插入图片描述
仪表盘有很多功能,如果要实现对hystrix熔断保护的实时监控,需要输入url地址即http://localhost:9000/actuator/hystrix.stream,点击Monitor Stream就会跳转到熔断保护的接口信息:

在这里插入图片描述
该接口服务在未访问的情况下是没有任何信息的,访问一下熔断保护的接口:
在这里插入图片描述

在这里插入图片描述
相关信息含义
在这里插入图片描述

对于上面的dashborad可以监控某个端口下的服务熔断,对于其他接口要实现监控就需要不断切换,这显然是很麻烦的,Hystrix也提供了Turbine方法帮助全局监控整个系统。

在这里插入图片描述

使用turbine也很简单分两步完成。

  • 导入依赖:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

  • 配置turbine
# turbine

# 如果监控多个微服务用逗号隔开
turbine.app-config=provider-service


turbine.cluster-name-expression=default

turbine会自动从注册中心自动获取需要监控的微服务,并聚合所有的微服务到/hystrix.stream接口。

Hystrix基本原理

服务隔离

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Hystrix使用命令模式的实现类 HystrixCommand 包装依赖调用逻辑,将每个类型的业务类型请求封装成对应的命令,每个命令在单独线程中执行 创建好的线程池被放入到
ConcurrentHashMap 中,当第二次查询请求过来时,可以直接从 Map中获取该线程池。

在这里插入图片描述
在这里插入图片描述
HystrixCommand 在执行过程中,执行业务代码的线程与请求线程(比如 Tomcat 线程)分离,请求线程可以自由控制离开的时间,这也就是通常所说的异步编程, Hystrix 是结合RxJava 来实现的异步编程,内部大量使用了 RxJava。RxJava 是一个响应式编程框架 ,可以参考其官方网站做进一步了解 Hystrix 通过设置线程池大小来控制并发访问 ,当线程饱和时可以拒绝服务,防止依赖问题扩散。Hystrix 使用线程池存储当前请求以及对请求做出处理 通过设置任务处理超时时间,并将堆积的请求放入线程池队列,可以应对突发流量。 当流量洪峰来临时,处理不完的请求可将数据存储到线程池中慢慢处理,当使用信号 Hystrix 使用原子计数器来记录当前运行线程数,新的请求到来时先判断计数器的数值,若超过设 定的最大线程数则丢弃该类型的新请求,若不超过则执行计数器+ l,请求返回时执行计数器一 1。信 号量隔离无法应对突发流量。

在这里插入图片描述
隔离策略的修改配置
在这里插入图片描述

服务熔断

在这里插入图片描述
在这里插入图片描述
结合服务隔离与服务熔断Hystrix的运行流程:

在这里插入图片描述

hystrix配置项

参考

部分图和内容取自微服务架构实战|郑天民 著

服务熔断Hystrix的替换方案Sentinel。

在这里插入图片描述

在这里插入图片描述
学习视频

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

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156246.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!