Spring Cloud — Hystrix 服务隔离、请求缓存及合并

news/2025/2/22 6:13:38

Hystrix 的核心是提供服务容错保护,防止任何单一依赖耗尽整个容器的全部用户线程。使用舱壁隔离模式,对资源或失败单元进行隔离,避免一个服务的失效导致整个系统垮掉(雪崩效应)。

1 Hystrix监控

Hystrix 提供了对服务请求的仪表盘监控。在客户端加入以下依赖:

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

并在客户端的Application类加上@EnableHystrixDashboard注解。

访问地址:http://localhost:8080/hystrix

在输入框中输入监控地址:http://localhost:8080/hystrix.stream,然后点击“Monitor Stream”按钮。

图 Hystrix 监控初始界面

图 Hystrix 仪表盘主要参数及含义

2 服务隔离

图 Hystrix 实现服务隔离的思路

2.1 隔离策略

Hystrix 提供了线程池隔离和信号量隔离两种隔离策略。

execution.isolation.strategy 属性配置隔离策略,默认为THREAD(线程池隔离),SEMAPHORE为信号量隔离。execution.isolation.thread.timeoutInMilliseconds属性配置请求超时时间,默认为1000ms。

2.1.1 线程池隔离

不同服务的执行使用不同的线程池,同时将用户请求的线程(如Tomcat)与具体业务执行的线程分开,业务执行的线程池可以控制在指定的大小范围内,从而使业务之间不受影响,达到隔离的效果。

优点

  1. 隔离优势,如果一个服务发生问题,只会影响该服务,而不会影响其他服务。
  2. 方便性能变化调整,可以更改对应command的参数(超时时间、重试次数、线程池大小等)。

缺点

线程及线程池的创建及管理增加了计算开销。

表 线程池隔离的优缺点

关于线程池隔离的相关配置有如下参数:

coreSize:线程池核心线程数。即线程池中保持存活的最小线程数。默认为10。

maximumSize:线程池允许的最大线程数。当核心线程数已满且任务队列已满时,线程池会尝试创建新的线程,直到达到最大线程数。默认为10。

maxQueueSize:线程池任务队列的大小。默认为-1,表示任务将被直接交给工作线程处理,而不是放入队列中等待。

queueSizeRejectionThreshold:即便没达到maxQueueSize阈值,但达到该阈值时,请求也会被拒绝,默认值为5。

图 新的请求在线程池的处理过程

是否创建新线程,是指当前活跃线程已达到coreSize,但线程数小于maximumSize,Hystrix 会创建新的线程来处理该任务。(这一步还受到queueSizeRejectionThreshold及maxQueueSize参数的影响)。

2.1.2 信号量隔离

用户请求线程和业务执行线程是同一线程,通过设置信号量的大小限制用户请求对业务的并发访问量,从而达到限流的保护效果。

优点

1 开销小,避免了线程创建、销毁及上下文切换等开销。

2 配置简单,只需要设置信号量大小即可。

3 适合轻量级操作,如内存或缓存服务访问,这些操作不太可能导致长时间延迟,因此信号隔离可以保持系统的高效性。

缺点

限流能力有限,存在阻塞风险,如果依赖服务阻塞,因为其没有使用线程池来隔离请求,那么可能会影响整个请求链路,导致系统性能下降。

表 Hystrix 信号隔离的优缺点

execution.isolation.semaphore.maxConcurrentRequests 最大并发请求数(信号量大小)。默认为10。

2.2 服务隔离的颗粒度

@HystrixCommand 注解还有三个属性:commandKey(标识该命令全局唯一的名称,默认情况下,同一个服务名称共享一个线程池)、groupKey(组名,Hystrix 会让相同组名的命令使用同一个线程池)、threadPoolKey(线程池名称,多个服务可以设置同一个threadPoolKey,来共享同一个线程池,在信号量隔离策略中不起作用)。

3 请求缓存

用户的同一个请求中,消费者可能会多次重复调用一个服务。Hystrix 提供的请求缓存可以在CommandKey/CommandGroup相同的情况下,直接共享第一次命令执行的结果,降低依赖调用次数。

java">@Service
public class UserService {

    private final RestTemplate restTemplate;

    public UserService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @CacheResult(cacheKeyMethod = "generateCacheKey")
    @HystrixCommand(commandKey = "info3",groupKey = "info3Group",commandProperties = {
            @HystrixProperty(name = "requestCache.enabled", value = "true")})
    public RequestResult<String> info3(String name) {
        System.out.println("发送请求:" + name);
        return RequestResult.success(restTemplate.getForObject("http://provider/user/info?name=" + name, String.class));
    }

    public String generateCacheKey(String name) {
        return name;
    }
}
java">@RequestMapping("/home")
@RestController
public class HomeController {

    private final RestTemplate restTemplate;
    private final UserService userService;

    public HomeController(RestTemplate restTemplate, UserService userService) {
        this.restTemplate = restTemplate;
        this.userService = userService;
    }

    @GetMapping("/info3")
    public RequestResult<String> info3(String name) {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        RequestResult<String> result = userService.info3(name);
        userService.info3(name);
        context.close();
        return result;
    }
}

 

4 请求合并

Hystrix针对高并发场景,支持将多个请求自动合并为一个请求,通过合并可以减少对依赖的请求,极大节省开销,提高系统效率。

请求合并主要是通过两部分实现:1)@HystrixCollapser 指定高并发请求的对应请求,其返回值为Futuer。2)@HystrixCommand 指定合并后的单个请求。其参数为第1部分请求参数的集合。

java">@Service
public class UserService {

    private final RestTemplate restTemplate;

    public UserService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @HystrixCollapser(
            collapserKey = "info",
            scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
            batchMethod = "batchInfo",collapserProperties = {
            @HystrixProperty(name = "timerDelayInMilliseconds", value = "1000"),
            @HystrixProperty(name = "maxRequestsInBatch", value = "3")
    })
    public Future<RequestResult<String>> batchInfo(String name) {
        // 不会被执行
        System.out.println("HystrixCollapser info");
        return null;
    }

    @HystrixCommand
    public List<RequestResult<String>> batchInfo(List<String> names) {
        System.out.println("批量发送:" + names);
        // 依赖也需要有一个支持批量的接口
        String res = restTemplate.getForObject("http://provider/user/info?name=" + names, String.class);
        List<RequestResult<String>> list = new ArrayList<>();
        int count = 0;
        for (String str : names) {
            list.add(RequestResult.success(res + "kk" + str + count++));
        }
        return list;
    }
}
java">@RequestMapping("/home")
@RestController
public class HomeController {

    private final RestTemplate restTemplate;
    private final UserService userService;

    public HomeController(RestTemplate restTemplate, UserService userService) {
        this.restTemplate = restTemplate;
        this.userService = userService;
    }

    @GetMapping("/info2")
    public RequestResult<String> info2(String name) throws ExecutionException, InterruptedException {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        Future<RequestResult<String>> future = userService.batchInfo(name);
        RequestResult<String> result = future.get();
        context.close();
        return result;
    }
}

http://www.niftyadmin.cn/n/5861756.html

相关文章

Nginx Embedded Variables 嵌入式变量解析(4)

Nginx Embedded Variables 嵌入式变量解析(4) 相关链接 nginx 嵌入式变量解析目录nginx 嵌入式变量全目录nginx 指令模块目录nginx 指令全目录 一、目录 1.1 变量目录 1.1.24 ngx_stream_core_module $binary_remote_addr $bytes_received $bytes_sent $connection $hos…

数据结构系列二:包装类+泛型

包装类泛型 一、包装类&#xff08;1&#xff09;基本数据类型和对应的包装类&#xff08;2&#xff09;装箱和拆箱 二、泛型&#xff08;1&#xff09;什么是泛型&#xff08;2&#xff09;引出泛型&#xff08;3&#xff09;语法&#xff08;4&#xff09;泛型类的使用1.语法…

SpringCloud-OpenFeign初步使用

在使用RestTemplate时,会发现拼接URL时非常不美观,并且在参数多了以后拼接起来也容易出错,而Feign就是为了解决这个问题,让远程调用像调用本地方法一样优雅且方便. 功能: 更优雅的进行远程调用 使用方法: 引入依赖,由于OpenFeign是基于负载均衡的所以要引入三个依赖,openFei…

【信息系统项目管理师-案例真题】2022下半年案例分析答案和详解

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 试题一(24分)【问题1】(6分)【问题2】(10分)【问题3】(8分)试题二(26分)【问题1】(8分)【问题2】(8分)【问题3】(4分)【问题4】(6分)试题三(25分)【问题1】(12分)【问题2】(7分)【问题…

高级SQL技术在Python项目中的应用:更进一步的数据分析与集成

引言 在第一篇中,我们深入探讨了ORM框架SQLAlchemy的高级用法以及性能优化策略。然而,要充分释放数据库的潜力,我们还需要掌握更多高级SQL特性,并将其与强大的数据分析工具生态系统有效集成。本篇将聚焦于窗口函数、CTE递归查询、JSON操作、全文搜索以及与Pandas的无缝集成…

【探商宝】2025年2月科技与商业热点头条:AI竞赛、量子计算与芯片市场新格局

一、 AI大模型竞争白热化&#xff1a;开源与闭源的博弈 OpenAI推进"星际之门"项目 为巩固美国在AI领域的领先地位&#xff0c;OpenAI正在全美评估数据中心选址&#xff0c;得州阿比林数据中心已开建。该项目被视为算力基建的关键布局&#xff0c;尽管面临DeepSeek低成…

Linux-Ansible命令

文章目录 常用命令基础命令 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Linux专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年02月21日18点49分 常用命令 ansible #主命令&#xff0c;管理员临时命令的执行工具 ansible-doc #…

【后端基础】布隆过滤器原理

文章目录 一、Bloom Filter&#xff08;布隆过滤器&#xff09;概述1. Bloom Filter 的特点2. Bloom Filter 的工作原理 二、示例1. 添加与查询2. 假阳性 三、Bloom Filter 的操作1、假阳性概率2、空间效率3、哈希函数的选择 四、应用 Bloom Filter 是一种非常高效的概率型数据…