这么秀的操作我竟然到现在才了解到?合并请求~

简介: 在几年前,我就看到过有些博客写关于合并请求的文章,一开始我没有太在意,最近在看一个up讲述关于商品模块的牛X设计,为了提高高并发的处理能力,一般会用redis 自增自减来实现库存扣减,但是他采用合并扣减库存,也就是同一时间n个扣减库存会合并成一个请求,这样无疑减少了IO次数,也提高系统性能

前言


在几年前,我就看到过有些博客写关于合并请求的文章,一开始我没有太在意,最近在看一个up讲述关于商品模块的牛X设计,为了提高高并发的处理能力,一般会用redis 自增自减来实现库存扣减,但是他采用合并扣减库存,也就是同一时间n个扣减库存会合并成一个请求,这样无疑减少了IO次数,也提高系统性能。然后今天我看淘系有篇文章讲述 怎么提高自己的系统架构水平,里面也提到合并更新操作

image.png

🐱那么这么秀的操作,真的不尝试下吗?Let's do it~

合并请求的目的


Why

A:你是否有遇到过类似场景,需要插入数据库很多很多条数据,那我们怎么优化?还有多个redis key请求的时候,如果我们每次都去拿到连接调用,可以发现时间会比较长,那怎么处理的?MQ场景,我们有一批的消息需要发送,是不是一个一个去投递?

答案是NO,我们会批量去处理这些任务,减少IO次数,其次批量处理可以减少往返网络通讯时间提高效率

通过简单demo感受下


秉着没吃过猪肉,也见过猪跑的想法,我们参照别人的思路:Future来实现异步调用,等到批量处理结果出来之后再返回。



show me your code


  1. 我们先想象下,需要什么变量,合并请求是随意合并吗? 答案当然不是,那么我们是将一段时间内的请求进行合并

    那么需要一个标识来表示是否符合这段时间,或者算法。比如说一秒内,都是这个需要合并请求的范围。下面就用i来计数,需求:比如说超过2个并发,我们就需要合并请求了

  2. 其次我们是不是要收集所有请求的对象,还有请求处理完,我们是不是要查询处理结果集,这样我们才好返回数据。所以加上LinkedList来缓存这一时刻的请求实体,以及使用set数据结构来模拟数据库db或者其他缓存处理结果的地方。


//某一时间段并发数量,可能1秒内
static int i = 0;

//这个一时刻的处理操作的队列
LinkedList<String> list = new LinkedList<>();

//可以代替DB,或者处理结果缓存地方
Set<String> set = new HashSet<>();
  1. 我们需要模拟一个业务处理器,定时执行list列表的任务,然后把结果丢到set结果集里头
CompletableFuture.runAsync(() -> {
    while (true) {
        if(!list.isEmpty()){
            Collections.shuffle(list);
            set.addAll(list);
            list.clear();
        }

    }
});
  1. 模拟并发合并请求操作
@GetMapping("firstRequest")
public boolean firstRequest() throws InterruptedException, ExecutionException, TimeoutException {
    //假设firstRequest,secondRequest同一个时间进来的
    i++;

    Thread.sleep(2000);
    if (i > 1) {
        list.add("firstRequest");
    }

    return CompletableFuture.supplyAsync(() -> {
        int i1 = 0;
        while (true) {
            i1++;
            if (i1 > 5) {
                return false;
            }
            if (set.remove("firstRequest")) {
                return true;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).get();
}

@GetMapping("secondRequest")
public boolean secondRequest() throws ExecutionException, InterruptedException, TimeoutException {
    i++;
    if (i > 1) {
        list.add("secondRequest");
    }

    return CompletableFuture.supplyAsync(() -> {
        int i1 = 0;
        while (true) {
            i1++;
            if (i1 > 5) {
                return false;
            }
            if (set.remove("secondRequest")) {
                return true;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).get();
}


🙋‍♂️ 我们看下第一个请求跟第二个请求,都做了啥操作?

首先第一个请求,会给i+1,代表当前时间段的计算器请求+1,然后等待一段时间,其实是为了,等第二个请求访问,让计算器达到并发等于2的场景。

然后分别将第一个跟第二个任务丢到list请求列表里头,然后我们异步任务去模拟业务处理,然后将处理结果丢到set结果返回集合中。请求通过future来定时请求返回结果,尝试5次,如果在这5次里头有结果,返回true。如果没有,则返回false。

到此我们代码实现完成了合并请求的逻辑。

合并请求的弊端


通过上面的例子,相信读者也看到有很多处等待重试拿数据的过程,比如说等待结果返回。

这个弊端都凸显出来了,如果数据量很大或者需要处理的任务很多的情况下,大家都在等待,那么服务器的资源一直被消耗,连接也会殆尽

所以,我们需要有个合理的过期时间,比如说超过多少秒,请求的线程就不再等待直接返回超时,然后有补偿机制再次去查询处理结果。

相关文章
|
缓存 NoSQL 关系型数据库
面试必问:Redis 如何实现库存扣减操作?
面试必问:Redis 如何实现库存扣减操作?
1809 7
面试必问:Redis 如何实现库存扣减操作?
|
SQL 缓存 数据库
OBCP第三章 SQL引擎高级技术-执行计划
OBCP第三章 SQL引擎高级技术-执行计划
504 0
|
Java Maven 数据库
【快速使用ShardingJDBC的哈希分片策略进行分表】
【快速使用ShardingJDBC的哈希分片策略进行分表】
359 0
|
网络协议 网络安全 Windows
|
5月前
|
消息中间件 负载均衡 中间件
⚡ 构建真正的高性能即时通讯服务:基于 Netty 集群的架构设计与实现
本文介绍了如何基于 Netty 构建分布式即时通讯集群。随着用户量增长,单体架构面临性能瓶颈,文章对比了三种集群方案:Nginx 负载均衡、注册中心服务发现与基于 ZooKeeper 的消息路由架构。最终选择第三种方案,通过 ZooKeeper 实现服务注册发现与消息路由,并结合 RabbitMQ 支持跨服务器消息广播。文中还详细讲解了 ZooKeeper 搭建、Netty 集群改造、动态端口分配、服务注册、负载均衡及消息广播的实现,构建了一个高可用、可水平扩展的即时通讯系统。
606 0
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
1044 69
从单体到微服务:如何借助 Spring Cloud 实现架构转型
|
9月前
|
Ubuntu 关系型数据库 MySQL
容器技术实践:在Ubuntu上使用Docker安装MySQL的步骤。
通过以上的操作,你已经步入了Docker和MySQL的世界,享受了容器技术给你带来的便利。这个旅程中你可能会遇到各种挑战,但是只要你沿着我们划定的路线行进,你就一定可以达到目的地。这就是Ubuntu、Docker和MySQL的灵魂所在,它们为你开辟了一条通往新探索的道路,带你亲身感受到了技术的力量。欢迎在Ubuntu的广阔大海中探索,用Docker技术引领你的航行,随时准备感受新技术带来的震撼和乐趣。
390 16
|
存储 消息中间件 运维
从单体到微服务:架构演进中的技术挑战与解决方案
在软件开发的过程中,系统架构的选择对项目的成功与否起到至关重要的作用。本文将深入探讨从单体架构向微服务架构演进过程中所遇到的技术挑战,并提供相应的解决方案。
518 27
|
运维 Oracle 关系型数据库
LIS(全称Laboratory Information Management System)系统源码
LIS(全称Laboratory Information Management System),是专为医院检验科设计的一套实验室信息管理系统,能将实验仪器与计算机组成网络,使病人样本登录、实验数据存取、报告审核、打印分发,实验数据统计分析等繁杂的操作过程,实现智能化、自动化和规范化管理。有助于提高实验室的整体管理水平,减少差错率,提高检验质量。
446 1
|
监控 Java 双11
Sentinel底层如何计算京东双十一线上系统实时QPS
【10月更文挑战第19天】随着电子商务行业的快速发展,双十一已成为全球最大的购物狂欢节。京东作为中国领先的电商平台,每年的双十一活动都会迎来巨大的流量高峰。为了保障系统在高并发情况下的稳定运行,京东采用了多种技术手段来应对。
220 0