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

news/2024/7/7 20:20:38

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://lihuaxi.xjx100.cn/news/1721015.html

相关文章

Windows下如何编译FFmpeg

ffmpeg一般在linux环境中使用&#xff0c;但是我们目前很多的开发工具是windows&#xff0c;为了方便在windows下调试和使用ffmpeg&#xff0c;我们需要再windows下面编译和使用ffpeg&#xff0c;本文只讲述windows下如何编译ffmpeg的内容。   windows下编译ffmpeg有很多的方…

代码随想录Day29 贪心04 LeetCode T860 柠檬水找零 T406 根据身高重建队列 T452 用最少得箭引爆气球

LeetCode T860 柠檬水找零 题目链接:860. 柠檬水找零 - 力扣&#xff08;LeetCode&#xff09; 题目思路: 这道题我们只要顺序按照数组判断是否能有钱找零即可,我们定义三个变量来记录每张钞票目前的数量,其中我们知道给10元得找5元,给二十元得找515元,而15元的组合有10元5元和…

涨幅25%,2023全球电动车销量将飙升至2000万辆 | 百能云芯

近日&#xff0c;工研院在「眺望2024产业发展趋势研讨会」上发布消息&#xff0c;预测随着全球晶片短缺的逐渐缓解&#xff0c;以及俄乌地区供应链产能向其他国家的部分转移&#xff0c;全球汽车市场在疫情的影响下逐渐回暖。根据工研院的数据&#xff0c;2023年全球汽车销量预…

设计模式——访问者模式(Visitor Pattern)+ Spring相关源码

文章目录 一、访问者模式&#xff08;Visitor Pattern&#xff09;二、文字描述三、例子例子一&#xff1a;菜鸟教程对象定义访问者定义使用总结 例子二&#xff1a;Spring的BeanDefinitionVisitor 一、访问者模式&#xff08;Visitor Pattern&#xff09; 行为型模式。 目的&…

Linux多线程【生产者消费者模型】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f383;操作环境&#xff1a; CentOS 7.6 腾讯云远程服务器 文章目录 &#x1f307;前言&#x1f3d9;️正文1、生产者消费者模型1.1、什么是生产者消费者模型&#xff1f;1.2、生产者消费…

人大女王金融硕士项目——无论你身处何时何地,都要相信自己的能力和潜力

成功不是一蹴而就的&#xff0c;它需要我们付出艰辛的努力和不断的追求。在这个过程中&#xff0c;我们需要拥有一颗坚定的信念和不屈不挠的精神。只有这样&#xff0c;我们才能在困境中迎难而上&#xff0c;在挫折中不断成长.作为在职人士的你&#xff0c;会选择报考人大女王金…

写一个自己的编码风格校验工具

文章目录 1. 目标2. 代码实现3. 结果验证1. 目标 我们知道java编译器把Java程序源码编译成字节码的时候,会对Java程序源码做各方面的检查校验,这些校验主要是以程序“写得对不对”为出发点,但不会校验程序“写得好不好”。有鉴于此,业界出现了许多针对程序“写得好不好”的…

iOS自动混淆测试处理笔记

1 打开 ipa&#xff0c;导出ipa 路径和配置文件路径会自动填充 2 点击 开始自动混淆测试处理 自动混淆测试是针对 oc 类和oc方法这两个模块进行自动混淆ipa&#xff0c;并ipa安装到设备中运行&#xff0c;通过检测运行ipa包是否崩溃&#xff0c;来对oc类和oc方法进行筛选。如果…