栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringCloud:Hystrix组件实现服务熔断

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringCloud:Hystrix组件实现服务熔断

SpringCloud:Hystrix组件实现服务熔断 一、Hystrix概述

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

Hystrix设计目标

  • 资源隔离、MQ解耦、不可用服务调用快速失败等。资源隔离通常指不同服务调用采用不同的线程池;不可用服务调用快速失败一般通过熔断器模式结合超时机制实现
  • 阻止故障的连锁反应
  • 快速失败并迅速恢复
  • 回退并优雅降级
  • 提供近实时的监控与告警

Hystrix如何实现这些设计目标?

  • 使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或HystrixObservableCommand对象中,并将该对象放在单独的线程中执行
  • 每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)
  • 记录请求成功,失败,超时和线程拒绝
  • 服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求
  • 请求失败,被拒绝,超时或熔断时执行降级逻辑
  • 近实时地监控指标和配置的修改
1.雪崩效应

分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应

2.雪崩效应常见场景及解决措施
  • 硬件故障:如服务器宕机,机房断电,光纤被挖断等

    解决措施:多机房容灾、异地多活等
    
  • 流量激增:如异常流量,重试加大流量等

    解决措施:服务自动扩容、流量控制(限流、关闭重试)等
    
  • 缓存穿透:一般发生在应用重启,所有缓存失效时,以及短时间内大量缓存失效时。大量的缓存不命中,使请求直击后端服务,造成服务提供者超负荷运行,引起服务不可用

    解决措施:缓存预加载、缓存异步加载等
    
  • 程序BUG:如程序逻辑导致内存泄漏,JVM长时间FullGC等

    解决措施:修改程序bug、及时释放资源等
    
  • 同步等待:服务间采用同步调用模式,同步等待造成的资源耗尽

    解决措施:资源隔离、MQ解耦、不可用服务调用快速失败等。
    		资源隔离通常指不同服务调用采用不同的线程池;
    		不可用服务调用快速失败一般通过熔断器模式结合超时机制实现
    
二、Hystrix容错

Hystrix的容错主要是通过添加容许延迟和容错方法,帮助控制这些分布式服务之间的交互。 还通过隔离服务之间的访问点,阻止它们之间的级联故障以及提供回退选项来实现这一点,从而提高系统的整体弹性

Hystrix主要提供了以下几种容错方法:

  • 资源隔离:
    • 线程池隔离
    • 信号量隔离
  • 降级:异常,超时
  • 熔断
三、Hystrix-资源隔离 线程隔离-线程池

Hystrix通过命令模式对发送请求的对象和执行请求的对象进行解耦,将不同类型的业务请求封装为对应的命令请求。

  • Hystrix为每个依赖服务调用分配一个小的线程池,如果线程池已满调用将被立即拒绝,默认不采用排队,加速失败判定时间
  • 用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,或者请求超时,则会进行降级处理
线程隔离-信号量

当依赖延迟极低的服务时,线程池隔离技术引入的开销超过了它所带来的好处。这时候可以使用信号量隔离技术来代替,通过设置信号量来限制对任何给定依赖的并发调用量

public class QueryByOrderIdCommandSemaphore extends HystrixCommand {
    private final static Logger logger = LoggerFactory.getLogger(QueryByOrderIdCommandSemaphore.class);
    private OrderServiceProvider orderServiceProvider;
 
    public QueryByOrderIdCommandSemaphore(OrderServiceProvider orderServiceProvider) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("orderService"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("queryByOrderId"))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withCircuitBreakerRequestVolumeThreshold(10)至少有10个请求,熔断器才进行错误率的计算
                        .withCircuitBreakerSleepWindowInMilliseconds(5000)//熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试
                        .withCircuitBreakerErrorThresholdPercentage(50)//错误率达到50开启熔断保护
                        .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)
                        .withExecutionIsolationSemaphoreMaxConcurrentRequests(10)));//最大并发请求量
        this.orderServiceProvider = orderServiceProvider;
    }
 
    @Override
    protected Integer run() {
        return orderServiceProvider.queryByOrderId();
    }
 
    @Override
    protected Integer getFallback() {
        return -1;
    }
}

由于Hystrix默认使用线程池做线程隔离,使用信号量隔离需要显示地将属性execution.isolation.strategy设置为ExecutionIsolationStrategy.SEMAPHORE,同时配置信号量个数,默认为10。客户端需向依赖服务发起请求时,首先要获取一个信号量才能真正发起调用,由于信号量的数量有限,当并发请求量超过信号量个数时,后续的请求都会直接拒绝,进入fallback流程。

信号量隔离主要是通过控制并发请求量,防止请求线程大面积阻塞,从而达到限流和防止雪崩的目的

线程隔离总结
线程切换支持异步支持超时支持熔断限流开销
信号量
线程池
四、Hystrix-降级实现 环境搭建

具体如何搭建,eureka环境搭建

1.服务端降级

在服务提供方,引入 hystrix 依赖

	
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix
            2.2.2.RELEASE
        

定义降级方法

public Goods findOne_fallback(int id){
    Goods goods = new Goods();
    goods.setTitle("降级了~~~");

    return goods;
}

使用 @HystrixCommand 注解配置降级方法

    @GetMapping("/findOne/{id}")
    @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
            //设置Hystrix的超时时间,默认1s
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public Goods findOne(@PathVariable("id") int id){
        //1.造个异常
        int i = 3/0;
        try {
            //2. 休眠2秒
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Goods goods = new Goods(id, "苹果手机", 3999, 10000);
        goods.setTitle(goods.getTitle() + ":" + "8899");//
        return goods;
    }

在启动类上开启Hystrix功能:@EnableCircuitBreaker

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker 开启Hystrix功能
public class HystrixProvider02Application {

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

测试结果

get请求:127.0.0.1:8002/order/goods/1
响应结果:
{
	"id": 0,
	"title": "降级了~~~provider02",
	"price": 0,
	"count": 0
}
2.消费端降级

消费方一般使用feign调用服务, feign 组件中已经集成了 hystrix 组件。我们不需要再引入依赖

定义feign 调用接口实现类,复写方法,即 降级方法

package com.mye.hystrixconsumer.feign;
import com.mye.hystrixconsumer.pojo.Goods;
import org.springframework.stereotype.Component;


@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {

    @Override
    public Goods findOne(int id) {
        Goods goods = new Goods();
        goods.setTitle("又被降级了~~~");
        return goods;
    }
}

在 @FeignClient 注解中使用 fallback 属性设置降级处理类。

package com.mye.hystrixconsumer.feign;
import com.mye.hystrixconsumer.config.FeignLogConfig;
import com.mye.hystrixconsumer.pojo.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;


@FeignClient(value = "EUREKA-PROVIDER", configuration = FeignLogConfig.class,fallback = GoodsFeignClientFallback.class)
public interface GoodsFeignClient {

    @GetMapping("/goods/findOne/{id}")
    public Goods findOne(@PathVariable("id") int id);
}

配置开启 feign.hystrix.enabled = true

# 开启feign对hystrix的支持
feign:
  hystrix:
    enabled: true

测试结果

get请求:127.0.0.1:8002/order/goods/1
响应结果:
{
	"id": 0,
	"title": "又被降级了~~~",
	"price": 0,
	"count": 0
}
五、Hystrix-熔断 1.熔断器简介

Hystrix在运行过程中会向每个commandKey对应的熔断器报告成功、失败、超时和拒绝的状态,熔断器维护并统计这些数据,并根据这些统计信息来决策熔断开关是否打开。如果打开,熔断后续请求,快速返回。隔一段时间(默认是5s)之后熔断器尝试半开,放入一部分流量请求进来,相当于对依赖服务进行一次健康检查,如果请求成功,熔断器关闭

修改服务提供者中的controller

@GetMapping("/{id}")
    @HystrixCommand(fallbackMethod = "circuitBreakerFallback",commandProperties = {
            //开启熔断
            @HystrixProperty(name="circuitBreaker.enabled",value = "true"),
            //设置Hystrix的超时时间,默认1s
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
            //监控时间 默认5000 毫秒
            @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
            //失败次数。默认20次
            @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "10"),
            //失败率 默认50%
            @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50") })
    public String circuitBreaker(@PathVariable("id") Integer id) {
        if (id<0){
            throw  new RuntimeException("id ="+id+",不能为负数");
        }
        return "调用成功 id=" + id;
    }
    public String circuitBreakerFallback(@PathVariable("id") Integer id) {
        return "id =" + id + ", 不能为负数";
    }

修改服务消费者的feign接口

@FeignClient(value = "EUREKA-PROVIDER",
        configuration = FeignLogConfig.class
        )
public interface GoodsFeignClient {

    @GetMapping("/goods/findOne/{id}")
    public Goods findOne(@PathVariable("id") int id);

    @GetMapping("/goods/threeseconds")
    public String threeseconds();

    @GetMapping("/goods/{id}")
    public String circuitBreaker(@PathVariable("id") Integer id);
}

修改服务消费者的controller

@GetMapping("/{id}")
    public String circuitBreaker(@PathVariable("id") int id){
        return goodsFeignClient.circuitBreaker(id);
    }

这里需要注意的是在配置文件中开启feign对hystrix的支持

feign:
  hystrix:
    enabled: true

注意 : 以上配置如果配置在@HystrixCommand注解中, 只对当前方法有效, 如果想对所有控制方法配置降级参数, 可以在application.yml总统一配置 , 配置如下 :

hystrix:
  command:
    default:
      circuitBreaker:
        errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
        sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒
        requestVolumeThreshold: 10 # 熔断触发最小请求次数,默认值是20
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000 # 熔断超时设置,默认为1秒
2.测试

正常访问

错误访问

多次错误访问之后

六、HystrixDashboard-服务监控

创建一个hystrix-dashboard模块

pom文件

   
        
            org.springframework.cloud
            spring-cloud-netflix-hystrix-dashboard
            2.2.7.RELEASE
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
    

application.yml

server:
  port: 9001

hystrix:
  dashboard:
    proxy-stream-allow-list: "localhost"

启动类

package com.mye.hystrixdashboard;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {

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

}

访问浏览器

地址:http://127.0.0.1:9001/hystrix

在服务提供者里添加HystrixConfig配置文件,重启服务

@Configuration
public class HystrixConfig {
    @Bean
    public ServletRegistrationBean myServlet(){
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

dashboard添加hystrix-provider02

http://localhost:8001/hystrix.stream
这里端口为服务提供者的端口

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/340368.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号