请求合并的总结

这几天基本每天都会看视频跟着学习一些东西,然后总结一下。

今天的总结是关于请求合并。

业务背景:优化接口的处理。预防系统为线程开销过大导致OOM。

处理思路:时间换空间的一种处理方式,在方法级别上 将同一时间请求的参数暂时堆积一起,然后合并成一个批量请求到数据库或者下游业务上。将线程开销的压力阻塞在上游服务上。

应用场景:部分业务在高并发的情况下会因为系统线程开销出现问题,但是专门为这个业务去增设服务器后,业务平峰的情况下服务器完全闲置产生性能浪费。出现的一种解决方案。

优缺点:优点我理解就是处理性能上的提升,系统开销的减少。缺点:我理解多次请求合并成一个。查询功能还好,

如果是复杂的业务,有一个失败导致的异常,会导致别的参数也失败。那么需要使用者对接口的业务实现做到知根知底。

 

首先我们利用countdownlatch模拟一下1000个线程并发问题的业务场景。

或者我们可以利用测试的一些并发工具去做这些事情。

然后我们去看调用的requestSumService.getStr方法。

public String getStr(int id)throws Exception ;

很简单的一个根据id返回String的一个接口。里面的实现暂定返回 return id+"test";

正常的业务场景下,我们将在系统启动后,启动1000个线程进行并发访问。每个返回耗时基本在2-3毫秒。

如果查数据库的话,我们的数据库就要同时创建1000个线程进行处理。

这个时候我们在方法内部做一些改变。

思路:我们的方法新增一个全局的无界队列(LinkedBlockingQueue),在收到请求后,不进行处理,而是将参数封装成一个对象Request,然后将这个对象放入队列。

同时,我们在类的中间新增一个方法,加上@PostConstruct,内部实现一个定时器,每20ms从队列中取出收到的请求数据,将请求数据作为参数,调用一个批量处理的下游业务处理方法。从而实现合并请求。

上代码:

@Service
public class RequetSumService implements IRequestSumService {

    /**
     * 无界阻塞队列 用来存储临时保存的参数信息  先进先出
     *
     */
    private LinkedBlockingQueue<Request> queue = new LinkedBlockingQueue<>();

    /**
     * 参数传递和返回的中间介质
     */
    class Request{
        /**
         * 请求参数信息
         */
        public int id;
        /**
         * 线程future信息 分发返回信息用 @since 1.8
         */
        public CompletableFuture<String> future;
    }

    /**
     * 利用类初始加载时执行一次的特性 进行一个定时器的加载
     * 定时的业务:每20毫秒扫描一次队列的数据,取出请求参数 改成批量查询数据库或者第三方
     * 空间换时间
     */
    @PostConstruct
    public void timerMethod() {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(()->{
            int size = queue.size();
            if (size > 0) {
                List<Request> requestList = Lists.newArrayList();
                log.info("请求一次,本次请求数量-{}", size);
                for(int i = 0 ;i < size;i++){
                    requestList.add(queue.poll());
                }
                // 批量请求合并成一个请求去处理数据
                List<Integer> idList = Lists.newArrayList();
                for(Request request : requestList){
                    idList.add(request.id);
                }
                Map<Integer, String> resultMap = getStrByIdList(idList);
                // 收到集体返回的信息后 进行分发 这里涉及到多线程中间的通信和传值问题 这里用到futrue
                for(Request request : requestList){
                    request.future.complete(resultMap.get(request.id));
                }
            }
        },0,20, TimeUnit.MILLISECONDS);
    }

    /**
     * 单次请求的方法
     * 思路:将请求的数据 以数据的形式 放到类初始的队列中 然后利用futrue值传递带回来值
     *      在特定的业务场景下有用处
     * @param id
     * @return
     */
    public String getStr(int id) throws Exception {
        CompletableFuture<String> future = new CompletableFuture<>();
        Request request = new Request();
        request.id = id;
        request.future = future;
        //将参数合并 装入队列中 等待定时器合并执行
        queue.add(request);
        return future.get();
    }

    /**
     * 模拟数据库和其他业务方的批量获取方法 这里写成本地方法 没有判空和去重等校验
     * @param idList
     * @return
     */
    public Map<Integer, String> getStrByIdList(List<Integer> idList) {
        Map<Integer, String> resultMap = Maps.newHashMap();
        for (int id : idList) {
            resultMap.put(id, id + "test");
        }
        return resultMap;
    }
}

批量调用数据返回的是众多请求参数的一个结果集,那么如果来区分哪个请求对应哪个结果呢。

这里用到的是future.   ->CompletableFuture. @since1.8

默认我们Thread继承的是Runable,返回值是void,是达不到我们的要求的。

CompletableFuture可以异步等待返回值。上面我们在获取到结果集后,根据封装参数里带的future可以来设置value。

然后通过future.get()来获取值。

扩展:get()和join()都可以实现获取异步返回值。

两者的区别一个是报错的异常不一样,一个是get()是有等待时间的。两者在线程没有获取到值前,

都会调用wait(boolean flag)来获取值,flag为是否可以中断。get为true,false为false.  get()方法是会主动中断的。

要学习的地方还很多。知道越多才越发现自己的无知。

### 如何在 VS Code 中处理 Git 合并请求 在 Visual Studio Code (VS Code) 中,可以方便地通过内置的 Git 工具或者扩展来管理合并请求。以下是关于如何在 VS Code 中处理 Git 合并请求的相关说明。 #### 使用 VS Code 处理合并冲突 当执行 `git merge` 或者 `git pull` 的时候可能会遇到文件冲突的情况。在这种情况下,VS Code 提供了一个直观的方式帮助开发者解决这些冲突: - 打开有冲突的文件,在左侧编辑器区域会看到标记为红色波浪线的部分表示存在冲突的内容。 - 对于每一处冲突,可以选择保留当前分支 (`ours`) 的更改、接受传入分支 (`theirs`) 的更改,或是手动调整两者之间的差异[^1]。 ```bash # 解决冲突后完成合并操作 git add . git commit --no-edit ``` #### 配置自动 Rebase 而不是 Merge 如果希望每次拉取远程更新时都采用 rebase 方式而不是默认的 merge 方法,可以通过设置全局配置实现这一点: ```bash git config --global pull.rebase true ``` 这一步骤能够减少不必要的合并提交数量,并保持历史记录更加清晰整洁[^3]。 #### 利用 Patience Algorithm 减少错误合并可能性 对于那些已经显著分叉很久的分支来说,使用 patience algorithm 可能会有助于更精确地匹配行从而降低误合风险: ```bash git merge -Xpatience another_branch_name ``` 此选项会让 recursive 策略花费更多时间寻找最佳匹配路径以防止因无关紧要相似之处引起的不必要改动[^4]。 #### 克隆仓库到本地环境 如果你还没有克隆目标项目至本机上的话,那么第一步就是先复制该项目链接地址并通过命令行输入如下指令将其下载下来: ```bash git clone https://github.com/username/repository-name.git ``` 上述语句中的 URL 应替换为你实际想要获取代码库的具体位置信息[^2]。 ### 总结 综上所述,在 VS Code 内部高效应对 git 合并请求不仅限于单纯依赖 IDE 自身功能模块;还需要合理运用终端工具以及适当调整个人工作流习惯才能达到事半功倍的效果。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值