Hystrix解读

目录
`Hystrix` 简介
`Hystrix` 服务熔断产生的背景
引起雪崩效应常见场景
初探 `Hystrix`
`Hystrix` 设计目标,作用
`Hystrix` 如何实现这些设计目标
`Hystrix` 入门
项目概览
`Hystrix` 的使用(不整合 `Feign`)
`Hystrix-study-user` 服务的主启动类
`Hystrix-study-user` 服务的 `Feign` 的客户端接口
`Hystrix-study-user` 服务的服务降级类
`Hystrix-study-user` 服务的 `Service` 实现类
`Hystrix-study-user` 服务的配置文件
服务熔断测试
`@HystrixCommand` 注解的简单使用
`Hystrix-study-user` 服务的 `Service` 实现类添加方法
`Hystrix-study-activity` 服务的 `Controller` 类
服务降级测试
修改 `Hystrix-study-activity` 服务的 `Controller` 类再测试
`@HystrixCommand` 注解的常见使用
`Hystrix` 与 `Ribbon` 的超时时间
`Hystrix` 的断路器工作原理
断路器开启的条件
断路器关闭的条件
服务降级与服务熔断区别
服务熔断
服务降级
区别
相同点
不同点
Hystrix 简介
Hystrix 是 Netlifx 开源的一款容错框架,防雪崩利器,具备服务降级,服务熔断,依赖隔离,监控 Hystrix Dashboard 等功能

官网:https://github.com/Netflix/Hystrix/wiki/How-To-Use

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

引起雪崩效应常见场景
硬件故障:如服务器宕机,机房断电,光纤被挖断等
流量激增:如异常流量,重试加大流量等
缓存击穿:一般发生在应用重启,所有缓存失效时,以及短时间内大量缓存失效时。大量的缓存不命中,使请求直击后端服务,造成服务提供者超负荷运行,引起服务不可用
程序 BUG:如程序逻辑导致内存泄漏,JVM 长时间 FullGC 等
同步等待:服务间采用同步调用模式,同步等待造成的资源耗尽
初探 Hystrix
Hystrix 设计目标,作用
服务的降级
服务的熔断
服务的限流
提供近实时的监控与告警
Hystrix 如何实现这些设计目标
使用命令模式将所有对外部服务(或依赖关系)的调用包装在 HystrixCommand 或HystrixObservableCommand 对象中,并将该对象放在单独的线程中执行
每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)
记录请求成功,失败,超时和线程拒绝
服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求
请求失败,被拒绝,超时或熔断时执行降级逻辑
近实时地监控指标和配置的修改
Hystrix 入门
项目概览


Hystrix 的使用(不整合 Feign)
在使用 Feign 组件作为接口调用远程服务时,是不需要添加 Hystrix 的依赖的。因为 Feign 默认已经集成了 Hystrix 和 Ribbon。如果单独使用 Hystrix 组件时,可以导入以下依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
1
2
3
4
Hystrix-study-user 服务的主启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableCircuitBreaker // 开启断路器
@EnableHystrixDashboard // 开启 Hystrix 的监控仪表盘
public class UserApplication {

    private static final Logger log = LoggerFactory.getLogger(UserApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
        log.info("===============springcloud user启动了=================");
    }

    // 解决 hystrix-dashBoard 仪表盘不能访问
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Hystrix-study-user 服务的 Feign 的客户端接口
@FeignClient(name = "STUDY-ACTIVITY", fallback = UserFeignFallback.class)
public interface UserFeign {

    @RequestMapping(path = { "/activity/getCoupon" }, method = RequestMethod.POST)
    String getCoupon(@RequestBody Integer id);

    @RequestMapping(path = { "/activity/getCouponTimeOut" }, method = RequestMethod.POST)
    String getCouponTimeOut(@RequestBody Integer id);

    @RequestMapping(path = { "/demo/timeOut" }, method = RequestMethod.POST)
    String timeOut(@RequestParam Integer mills);

    @RequestMapping(path = { "/timeOut" }, method = RequestMethod.POST)
    String tripTest(@RequestParam Integer mills);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Hystrix-study-user 服务的服务降级类
@Component
public class UserFeignFallback implements UserFeign {

    @Override
    public String getCoupon(Integer id) {
        return null;
    }

    @Override
    public String getCouponTimeOut(Integer id) {
        return "------超过2000毫秒时,直接进入服务降级处理------";
    }

    @Override
    public String timeOut(Integer mills) {
        return "---------------您的请求【超时】或【失败】,已进入服务降级模式了----------------";
    }

    @Override
    public String tripTest(Integer mills) {
         return "-------------请求未通过-----------";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Hystrix-study-user 服务的 Service 实现类
@Service
public class UserServiceImpl implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserFeign userFeign;

    // 使用注解 @HystrixCommand 指定服务熔断的回退方法
    @HystrixCommand(fallbackMethod = "firstLoginError")
    @Override
    public String firstLogin(Integer id) {
        // 采用 Feign 客户端来调用服务 Hystrix-study-activity
        String result = userFeign.getCoupon(id);
        log.info("===================result的值为:" + result + "======================");
        return result;
    }

    // 当服务 Hystrix-study-activity 不可用时,这时让其回调回退方法
    public String firstLoginError(Integer id) {
        return "---------您请求的服务暂时不可用,请稍后再试--------------";
    }
}    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Hystrix-study-user 服务的配置文件
server.port=8080

spring.application.name=study-user

eureka.client.service-url.defaultZone=http://eureka7001.com:8761/eureka/
#事实上,springcloud默认已为Feign整合了Hystrix,要想为Feign打开Hystrix支持,只需要设置feign.hystrix.enabled=true即可。
feign.hystrix.enabled=true
#补充:在springcloud Dalston之前的版本中,Feign默认开启Hystrix支持,无需设置feign.hystrix.enabled=true.
#从springcloud Dalston版本开始,Feign的Hystrix支持默认关闭,需要手动设置开启

#配置Hystrix的超时时间
#default全局有效,service id指定应用有效
hystrix.command.default.execution.timeout.enabled=true #默认为true
#默认值为 1000毫秒(对于每一个标有注解 @FeignClient 的接口的所有抽象方法生效)
#hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=9000

#显示服务器详细的健康信息
management.endpoint.health.show-details=always

#暴露全部的监控信息(解决hystrix-dashBoard仪表盘不能访问)
management.endpoint.web.exposure.include="*"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
服务熔断测试
分别启动 Hystrix-study-activity,Hystrix-study-eureka,Hystrix-study-user 三个服务,使用 Postman 测试如下


此时再关闭 Hystrix-study-activity 服务


说明执行了 @HystrixCommand(fallbackMethod = "firstLoginError") 服务熔断的回退方法

@HystrixCommand 注解的简单使用
依然使用上面的入门项目,只不过不需要引入 Hystrix 的依赖了,直接使用 Feign 客户端进行调用。在使用 Feign 组件作为接口调用远程服务时,是不需要添加 Hystrix 的依赖的。因为 Feign 默认已经集成了 Hystrix 和 Ribbon。如果单独使用 Hystrix 组件时,可以导入以下依赖

Hystrix-study-user 服务的 Service 实现类添加方法
execution.isolation.thread.timeoutInMilliseconds:该属性用来配置方法执行的超时时间。我们在之前对于降级处理时间的配置,都是在全局配置文件 application.yml 中配置的,commandProperties 可以让我们在一些具有独特要求的方法上,单独进行一些配置操作

// 设置Hystrix的服务降级超时时间,超过2000毫秒时,直接进入服务降级处理    
@HystrixCommand(commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") })
@Override
public String firstLoginTimeOut(Integer id) {
    String result = userFeign.getCouponTimeOut(id);
    log.info("===================result的值为:" + result + "======================");
    return result;
}
1
2
3
4
5
6
7
8
9
Hystrix-study-activity 服务的 Controller 类
@Controller
@RequestMapping(path = { "/activity" })
public class ActivityController {

    private static final Logger log = LoggerFactory.getLogger(ActivityController.class);

    @RequestMapping(path = { "/getCouponTimeOut" }, method = RequestMethod.POST)
    @ResponseBody
    public String getCouponTimeOut(@RequestBody Integer id) {
        try {
            Random random = new Random();
            TimeUnit.SECONDS.sleep(random.nextInt(10) % (7) + 4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("=============该用户首次登陆(注册),领取优惠券失败============");
        return "error";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
服务降级测试
分别启动 Hystrix-study-activity,Hystrix-study-eureka,Hystrix-study-user 三个服务,使用 Postman 测试如下


说明执行了 UserFeignFallback 服务降级处理类的相应方法

修改 Hystrix-study-activity 服务的 Controller 类再测试
@Controller
@RequestMapping(path = { "/activity" })
public class ActivityController {

    private static final Logger log = LoggerFactory.getLogger(ActivityController.class);

    @RequestMapping(path = { "/getCouponTimeOut" }, method = RequestMethod.POST)
    @ResponseBody
    public String getCouponTimeOut(@RequestBody Integer id) {
        log.info("=============该用户首次登陆(注册),领取优惠券成功============");
        return "SUCCESS";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
再测试结果

@HystrixCommand 注解的常见使用
@Service
public class UserServiceImpl implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserFeign userFeign;
   
    @HystrixCommand(threadPoolKey = "time", threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "2"),
            @HystrixProperty(name = "maxQueueSize", value = "20")}, commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "9000")})
    @Override
    public String timeOut(Integer mills) {
        log.info("-----------mills:的值为:" + mills + "--------------");
        return userFeign.timeOut(mills);
    }

    @HystrixCommand(threadPoolKey = "time_1", threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "2"),
            @HystrixProperty(name = "maxQueueSize", value = "20")}, commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "9000")})
    @Override
    public String timeOut_1(Integer mills) {
        log.info("-----------mills:的值为:" + mills + "--------------");
        return userFeign.timeOut(mills);
    }

  /**
    * Hystrix的断路器测试
    * 
    * 模拟测试:3秒钟内,请求次数达到2次,并且失败率在50%以上,断路器做跳闸动作。跳闸后的活动窗口设置为3秒
    *
    * 服务的健康状态检查:http://ip:port/actuator/health
    *     Hystrix的健康状态为:status: "UP"
    *     Hystrix的断路器跳闸后状态为:status: "CIRCUIT_OPEN"
    *     此时要删除服务的降级处理类 UserFeignFallback,才能查看健康状态
     */
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "3000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "3000")})
    @Override
    public String tripTest(Integer mills) {
        return userFeign.tripTest(mills);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
鉴于篇幅,文章不再赘述,详情可以查看:https://www.cnblogs.com/zhenbianshu/p/9630167.html

Hystrix 与 Ribbon 的超时时间
如果 hystrix.command.default.execution.timeout.enabled = true(默认),则会有两个执行方法超时的配置:一个就是 ribbon 的 ReadTimeout,一个就是熔断器 hystrix 的timeoutInMilliseconds,此时谁的值小谁生效
如果 hystrix.command.default.execution.timeout.enabled = false,则熔断器不进行超时熔断,而是根据 ribbon 的 ReadTimeout 抛出的异常而熔断,也就是取决于 ribbon
ribbon 的 ConnectTimeout 配置的是请求服务的超时时间,除非服务找不到,或者网络原因,这个时间才会生效
ribbon 还有 MaxAutoRetries 对当前实例的重试次数,MaxAutoRetriesNextServer 对切换实例的重试次数,如果 ribbon 的 ReadTimeout 超时,或者 ConnectTimeout 连接超时,会进行重试操作
由于 ribbon 的重试机制,通常熔断的超时时间需要配置的比 ReadTimeout 长,ReadTimeout 比 ConnectTimeout 长,否则还未重试就熔断了
为了确保重试机制的正常运作,理论上(以实际情况为准)建议 hystrix 的超时时间为:(1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout
Hystrix 的断路器工作原理


断路器开启的条件
当请求达到阀值时候:默认 10 秒内 20 次请求,当请求失败率达到默认 50% 的时,此时断路器将会开启,所有的请求都不会执行
断路器关闭的条件
当断路器开启 5 秒(默认)时,这时断路器是半开状态, 会允许其中一个请求执行
如果执行成功,则断路器会关闭;如果失败,则继续开启。循环重复这两个流程
服务降级与服务熔断区别
服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制,一般来说,每个服务都需要熔断机制的

如高压电路中,如果某个地方的电压过高,熔断器就会熔断,对电路进行保护。在微服务架构中,熔断机制也是起着类似的作用
当扇出链路的某个微服务不可用,或响应超时,或宕机,或异常时,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路
使用注解 @HystrixCommand(fallbackMethod = " ") 来指定服务熔断的回退方法

@Service
public class UserServiceImpl implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserFeign userFeign;

    // 使用注解 @HystrixCommand 指定服务熔断的回退方法
    @HystrixCommand(fallbackMethod = "firstLoginError")
    @Override
    public String firstLogin(Integer id) {
        // 采用 Feign 客户端来调用服务 Hystrix-study-activity
        String result = userFeign.getCoupon(id);
        log.info("===================result的值为:" + result + "======================");
        return result;
    }

    // 当服务 Hystrix-study-activity 不可用时,这时让其回调回退方法
    public String firstLoginError(Integer id) {
        return "---------您请求的服务暂时不可用,请稍后再试--------------";
    }
}    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
服务降级
降级是指自己的待遇下降了,从 RPC 调用环节来讲,就是说整体资源快不够了,忍痛将某些服务单元先关掉,关闭后还要返回一些可处理的备选方法,待渡过难关,再开启回来
降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)
@FeignClient(name = "STUDY-ACTIVITY", fallback = UserFeignFallback.class)
public interface UserFeign {

    @RequestMapping(path = { "/activity/getCouponTimeOut" }, method = RequestMethod.POST)
    String getCouponTimeOut(@RequestBody Integer id);

    @RequestMapping(path = { "/demo/timeOut" }, method = RequestMethod.POST)
    String timeOut(@RequestParam Integer mills);
}
1
2
3
4
5
6
7
8
9
@Component
public class UserFeignFallback implements UserFeign {

    @Override
    public String getCouponTimeOut(Integer id) {
        return "------超过2000毫秒时,直接进入服务降级处理------";
    }

    @Override
    public String timeOut(Integer mills) {
        return "---------------您的请求【超时】或【失败】,已进入服务降级模式了----------------";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
区别
相同点
目的很一致,都是从服务的可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段
最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用
不同点
触发原因不太一样:服务熔断一般是某个服务(下游服务)故障或异常引起,而服务降级一般是从系统整体负荷考虑的
管理层次不太一样:熔断其实是一个框架级的处理,每个服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)
————————————————
版权声明:本文为CSDN博主「柳若烟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38192427/article/details/114176876

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值