使用Hystrix实现请求合并,降低服务器并发压力

news2024/12/22 20:46:22

1.引入Hystrix 

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

2.在启动类上开启Hystrix功能

@EnableHystrix

3.请求合并实现代码

import com.bzcst.bop.oms.orm.model.po.Product;
import com.bzcst.bop.oms.orm.service.ProductService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.Future;

/**
 * @author 向振华
 * @date 2023/10/26 14:37
 */
@Slf4j
@Service
public class BatchService {

    @Resource
    private ProductService productService;

    @HystrixCollapser(
            batchMethod = "getByIds",
            scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
            collapserProperties = {
                    @HystrixProperty(name = HystrixPropertiesManager.MAX_REQUESTS_IN_BATCH, value = "10"),
                    @HystrixProperty(name = HystrixPropertiesManager.TIMER_DELAY_IN_MILLISECONDS, value = "20")
            }
    )
    public Future<Product> getById(Long id) {
        return null;
    }

    @HystrixCommand
    public List<Product> getByIds(List<Long> ids) {
        log.info("批查询 ---> " + ids);
        return productService.listByIds(ids);
    }
}

其中getById(Long id)方法并不会进入。 

其中ProductService 是基于mybatisplus的查询接口。

import com.bzcst.bop.oms.orm.model.po.Product;
import com.baomidou.mybatisplus.extension.service.IService;

public interface ProductService extends IService<Product> {

}

 4.调用

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.bzcst.bop.oms.orm.model.po.Product;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author 向振华
 * @date 2023/10/26 14:32
 */
@RestController
public class TestController {

    @Resource
    private BatchService batchService;

    @GetMapping("/product/{id}")
    public Object product(@PathVariable Long id) throws Exception {
        Future<Product> productFuture = batchService.getById(id);
        return productFuture.get();
    }

    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        // 模拟20个并发请求
        CountDownLatch countDownLatch = new CountDownLatch(20);
        for (int i = 1; i <= 20; i++) {
            int fi = i;
            executorService.execute(() -> {
                try {
                    countDownLatch.await();
                    HttpRequest httpRequest = HttpRequest.get("http://localhost:8080/bop-oms/product/" + fi);
                    String body = httpRequest.execute().body();
                    System.out.println(fi + " ---> " + body);
                } catch (Exception e) {
                }
            });
            countDownLatch.countDown();
        }
    }
}

日志记录可以看出是批量处理

2023-10-26 17:54:31.708  INFO 10524 --- [-BatchService-9] c.bzcst.bop.oms.controller.BatchService  : 批查询 ---> [10, 5, 9, 15, 4, 12, 11, 16, 8, 14]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@58dfec5b] was not registered for synchronization because synchronization is not active
parser sql: SELECT id, xxx FROM oms_product WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2023-10-26 17:54:31.712  INFO 10524 --- [-BatchService-8] c.bzcst.bop.oms.controller.BatchService  : 批查询 ---> [3, 18, 1, 13, 7, 19, 20, 2, 6, 17]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4235ea19] was not registered for synchronization because synchronization is not active
parser sql: SELECT id, xxx FROM oms_product WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
JDBC Connection [HikariProxyConnection@935862209 wrapping com.mysql.cj.jdbc.ConnectionImpl@130542a5] will not be managed by Spring
==>  Preparing: SELECT id, xxx FROM oms_product WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
==> Parameters: 10(Long), 5(Long), 9(Long), 15(Long), 4(Long), 12(Long), 11(Long), 16(Long), 8(Long), 14(Long)
JDBC Connection [HikariProxyConnection@205926351 wrapping com.mysql.cj.jdbc.ConnectionImpl@67b600cc] will not be managed by Spring
==>  Preparing: SELECT id, xxx FROM oms_product WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
==> Parameters: 3(Long), 18(Long), 1(Long), 13(Long), 7(Long), 19(Long), 20(Long), 2(Long), 6(Long), 17(Long)
<==    Columns: id, tenant_id, category_id, name, code, price, ladder_price, is_ladder_price, unit, is_enabled, description, version, create_by, create_time, update_by, update_time, delete_flag
<==        Row: 4, 1, 0, 转供电, 4, 4.00, , 0, , 1, , 1,  , 2022-12-29 17:01:09,  , 2022-12-29 17:01:09, 0
<==        Row: 5, 1, 0, 通下水道, XSD, 5.00, , 0, , 1, , 1,  , 2023-05-23 18:24:30,  , 2023-05-23 18:24:30, 0
<==        Row: 8, 1, 0, 门卡押金, 0302, 8.00, , 0, , 1, , 1,  , 2023-03-04 10:57:50,  , 2023-04-14 09:53:17, 0
<==        Row: 9, 1, 0, 阶梯单价, 12321, 9.00, , 1, , 1, , 1,  , 2023-10-13 16:39:09,  , 2023-10-13 16:39:09, 0
<==        Row: 10, 1, 0, 阿萨德, 123333, 10.00, , 0, , 1, , 1,  , 2023-09-14 10:43:01,  , 2023-09-14 10:43:01, 0
<==        Row: 11, 1, 0, 补贴空置费, 444, 11.00, , 0, , 1, , 1,  , 2023-03-02 17:05:10,  , 2023-03-02 17:05:10, 0
<==        Row: 12, 1, 0, 路灯费, B<N, 12.00, , 0, , 1, , 1,  , 2023-03-03 10:55:23,  , 2023-03-03 10:55:23, 0
<==        Row: 14, 1, 0, 零星物业, 3, 14.00, , 0, , 1, , 1,  , 2023-03-02 16:50:05,  , 2023-03-02 16:50:05, 0
<==        Row: 15, 1, 0, 零星电费, 2, 15.00, , 0, , 1, , 1,  , 2023-03-02 16:49:46,  , 2023-03-02 16:49:46, 0
<==        Row: 16, 1, 0, 非生活垃圾清运费, 16, 16.00, , 0, , 1, , 1,  , 2022-12-29 17:01:09,  , 2022-12-29 17:01:09, 0
<==      Total: 10
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@58dfec5b]
<==    Columns: id, tenant_id, category_id, name, code, price, ladder_price, is_ladder_price, unit, is_enabled, description, version, create_by, create_time, update_by, update_time, delete_flag
<==        Row: 1, 1, 0, 专项维修金, 1, 1.00, , 0, , 1, , 1,  , 2022-12-29 17:01:09,  , 2022-12-29 17:01:09, 0
<==        Row: 2, 1, 0, 车位空置费, 2, 2.00, , 0, , 1, , 1,  , 2022-12-29 17:01:09,  , 2022-12-29 17:01:09, 0
<==        Row: 3, 1, 0, 车位费, CWF01, 3.00, , 0, , 1, , 1,  , 2023-10-10 09:57:07,  , 2023-10-10 09:57:07, 0
<==        Row: 6, 1, 0, 服务费, 6, 6.00, , 0, , 1, , 1,  , 2022-12-29 17:01:09,  , 2022-12-29 17:01:09, 0
<==        Row: 7, 1, 0, 销售配合费, s, 7.00, , 0, , 1, , 1,  , 2022-12-29 17:01:09,  , 2022-12-29 17:01:09, 0
<==        Row: 13, 1, 0, 零星水费, 1, 13.00, , 0, , 1, , 1,  , 2023-03-02 16:49:18,  , 2023-03-02 16:49:18, 0
<==        Row: 17, 1, 0, 顾问费, 17, 17.00, , 0, , 1, , 1,  , 2022-12-29 17:01:09,  , 2022-12-29 17:01:09, 0
<==        Row: 18, 1, 0, 餐饮垃圾费, 18, 18.00, , 0, , 1, , 1,  , 2022-12-29 17:01:09,  , 2022-12-29 17:01:09, 0
<==        Row: 19, 1, 0, 租赁广告费用, 1000123, 19.00, [], 0, , 1, , 1,  , 2023-06-08 10:51:16,  , 2023-06-08 10:51:16, 0
<==        Row: 20, 1, 0, 租金, ZJ002, 20.00, [], 0, , 1, , 1,  , 2023-03-15 17:40:12,  , 2023-03-15 17:40:12, 0
<==      Total: 10
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4235ea19]

或者这样请求也可以

    @GetMapping("/product")
    public void product() throws Exception {
        List<Future> list = new ArrayList<>();
        for (long i = 1; i <= 20; i++) {
            Future<Product> productFuture = batchService.getById(i);
            list.add(productFuture);
        }

        for (Future future : list) {
            Object o = future.get();
            System.out.println(o);
        }
    }

如果scope是REQUEST方式,则需要使用HystrixRequestContext

    @GetMapping("/product")
    public void product() throws Exception {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        try {
            List<Future> list = new ArrayList<>();
            for (long i = 1; i <= 20; i++) {
                Future<Product> productFuture = batchService.getById(i);
                list.add(productFuture);
            }

            for (Future future : list) {
                Object o = future.get();
                System.out.println(o);
            }
        } finally {
            context.shutdown();
        }
    }

5.@HystrixCollapser参数介绍

batchMethod,请求合并方法

scope,请求合并方式,REQUEST:请求范围,GLOBAL:全局范围,默认com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL

collapserProperties
HystrixPropertiesManager.MAX_REQUESTS_IN_BATCH 最大请求合并数量,默认Integer.MAX_VALUE
HystrixPropertiesManager.TIMER_DELAY_IN_MILLISECONDS 请求合并间隔毫秒值,默认10ms

注意,达到请求合并间隔毫秒值,没达到最大请求合并数量时,也会进行请求合并

@HystrixCollapser是基于Spring的AOP实现的

com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect

6.请求合并工作流程图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1138888.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

走进国产机器人领军品牌华数机器人,共探数字化变革魔力

近日&#xff0c;纷享销客举办的“一院两司服务对接会暨走进纷享销客【数字化标杆】游学示范基地活动”在佛山顺利举行&#xff0c;本期活动走进华中数控旗下品牌、国家级专精特新“小巨人”企业华数机器人&#xff0c;特邀佛山华数机器人有限公司常务副总经理杨林、纷享销客广…

Ubuntu 内核降级到指定版本

reference https://www.cnblogs.com/leebri/p/16786685.html 前往此网站&#xff0c;找到所需的内核 https://kernel.ubuntu.com/~kernel-ppa/mainline/ 查看系统架构 dpkg --print-architecture 二、下载安装包 注意&#xff1a;下载除lowlatency以外的deb包 三、安装内核 3…

C++前缀和算法的应用:从栈中取出 K 个硬币的最大面值和 原理源码测试用例

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 题目 一张桌子上总共有 n 个硬币 栈 。每个栈有 正整数 个带面值的硬币。 每一次操作中&#xff0c;你可以从任意一个栈的 顶部 取出 1 个硬币&#xff0c;从栈中移除…

【智能座舱】- 汽车产业的变革,电动化是上半场,而智能化则是下半场

“汽车产业的变革,电动化是上半场,而智能化则是下半场”,已成为汽车行业的普遍共识。对于制造业企业,伴随业务发展、长时间的生产经营,往往积淀着海量专业性知识,同时存在知识管理集中化与结构化困难、缺乏系统化知识体系、关键业务知识依靠传授、检索效率低下、精准度不…

STM32的BOOT1和BOOT0查找及配置-都有BOOT1引脚的

STM32 BOOT0和BOOT1引脚查找 STM32是有BOO0和BOOT1的&#xff0c;有的芯片原理图没有标注BOOT1&#xff0c;但是可以正在手册查到BOOT0和BOOT1引脚的。 STM32 BOOT配置方式 1&#xff09;主Flash 主Flash起始地址为0x08000000&#xff0c;它指的是STM32内置Flash&#xff0c;通…

共享办公:一种新型的工作方式

随着互联网技术的发展和创业文化的兴起&#xff0c;越来越多的人选择了在共享办公室工作。共享办公室是一种提供灵活、便捷和经济的工作空间的服务模式&#xff0c;它可以让不同的个人或团队在同一地点共享办公设施和资源。那么&#xff0c;共享办公室是什么&#xff1f;它有什…

TSINGSEE青犀省级高速公路视频上云联网方案:全面实现联网化、共享化、智能化

一、需求背景 随着高速铁路的建设及铁路管理的精细化&#xff0c;原有的模拟安防视频监控系统已经不能满足视频监控需求&#xff0c;越来越多站点在建设时已开始规划高清安防视频监控系统。高速公路视频监控资源非常丰富&#xff0c;需要对其进行综合管理与利用。通过构建监控…

国际腾讯云直播推流配置教程!

云直播的服务本质是一个广播的过程&#xff0c;类似于电视台的直播节目通过有线电视网发送给千家万户。为了完成这个过程&#xff0c;云直播需要有采集和推流设备&#xff08;类似摄像头&#xff09;、云直播服务&#xff08;类似电视台的有线电视网&#xff09;和播放设备&…

银河麒麟v10x86或者arm离线安装服务

银河麒麟v10x86或者arm离线安装服务 最近有个项目&#xff0c;甲方的服务器用的全是国产化服务器银河麒麟&#xff0c;架构是x86的然后也无法连接外网&#xff0c;需要离线安装服务正常思路就是找到离线安装的包&#xff0c;然后拷贝到现场的服务器中进行安装所以问题就在于如…

【计算机网络笔记】Web应用之HTTP协议(涉及HTTP连接类型和HTTP消息格式)

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

C++ Qt/VTK装配体组成联动连接杆

效果 关键代码 #include "View3D.h" #include "Axis.h"#include <vtkActor.h> #include <vtkAppendPolyData.h > #include <vtkAreaPicker.h> #include <vtkAxesActor.h> #include <vtkBox.h> #include <vtkCamera.h>…

使用内网穿透本地MariaDB数据库,并实现在公网环境下使用navicat图形化工具

公网远程连接MariaDB数据库【cpolar内网穿透】 文章目录 公网远程连接MariaDB数据库【cpolar内网穿透】1. 配置MariaDB数据库1.1 安装MariaDB数据库1.2 测试局域网内远程连接 2. 内网穿透2.1 创建隧道映射2.2 测试随机地址公网远程访问3. 配置固定TCP端口地址3.1 保留一个固定的…

基于单片机的智能电子鼻的设计

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、智能电子鼻系统的设计方案1.1智能电子鼻系统的设计思路1.2智能电子鼻系统的设计流程图1.3智能电子鼻系统的硬件数…

软考高项-计算题理解

动态回收期主要是看净现值&#xff0c;仔细看&#xff0c;04年投资了925.93 &#xff0c;05,06合计共有825.59&#xff0c;也就是说2年还不能收完&#xff0c;剩余的部分要2年&#xff08;925.93-428.67-396.92&#xff09;2.27&#xff0c;也就是说这道题选C (6-1.1-0.35-0.05…

Jetpack:018-Jetpack中的导航一

文章目录 1. 概念介绍2. 使用方法2.1 基本概念2.2 传统用法2.3 新的用法 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack库中对话框相关的内容&#xff0c;本章回中主要介绍 导航。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff01; 1. 概念介绍 我…

基于 Redis + Lua 脚本实现分布式锁,确保操作的原子性

1.加锁的Lua脚本&#xff1a; lock.lua --- -1 failed --- 1 success--- getLock key local result redis.call(setnx , KEYS[1] , ARGV[1]) if result 1 then--PEXPIRE:以毫秒的形式指定过期时间redis.call(pexpire , KEYS[1] , 3600000) elseresult -1;-- 如果value相同&…

动态规划(数位统计Dp)

AcWing 338. 计数问题 思路分析&#xff1a; 代码展示&#xff1a; #include <iostream> #include <algorithm> #include <cstring> #include <vector>using namespace std;//10的x次方 int pow10(int x) {int res 1;while(x --) res * 10;retur…

NIO和BIO编程

一、网络通信编程基本常识 1、什么是Socket&#xff1f; Socket是应用层与TCP/IP协议族通信的中间软件抽象层&#xff0c;它是一组接口&#xff0c;一般由操作系统提供。 2、短连接 短连接是指socket建立连接之后传输数据确定接收完后关闭连接 3、长连接 长连接是指建立so…

全新高速HID调试工具

全新高速 HID 调试工具&#xff0c;程序袁USB开发利器 支持一下特性&#xff1a; 支持高速USB自适应HID报告长度自动定时发送内置CRC小工具自定义显示 高速USB HID调试工具下载

Pytorch - 数据增广

增加一个已有数据集&#xff0c;使得有更多的多样性 在语言里面加入各种不同的背景噪音改变图片的颜色和形状 翻转 左右翻转上下翻转 但是并不总是可行的。 切割 从图片中切割一块&#xff0c;然后变形到固定形状 随机高宽比随机大小随机位置 颜色 改变色调、饱和度、明…