面试官问我:什么是高并发下的请求合并? (上)

简介: 面试官问我:什么是高并发下的请求合并? (上)

从一道面试题说起


前段时间一个在深圳的,两年经验的小伙伴出去面试了一圈,收割了几个大厂 offer 的同时,还总结了一下面试的过程中遇到的面试题,面试题有很多,文末的时候我会分享给大家。

这次的文章主要分享他面试过程中遇到的一个场景题:

image.jpeg


他说对于这个场景题,面试的时候没有什么思路。

说真的,请求合并我知道,高并发无非就是快速的请求合并。

但是在我有限的认知里面,如果类似于秒杀的高并发扣库存这个场景,用请求合并的方式来做,我个人感觉是有点怪怪的不够传统。

在传统的,或者说是业界常用的秒杀解决方案中,从前端到后台,你也找不到请求合并的字样。

我理解请求合并更加适用的场景是查询类的,或者说是数值增加类的需求,对于库存扣减这种,你稍不留神,就会出现超卖的情况。

当然也有可能是我理解错题意了,看到高并发扣库存就想到秒杀场景了。

但是不重要,我们也不能直接和面试官硬刚。


image.png

我会重新给个我觉得合理的场景,告诉大家我理解的请求合并和高并发下的请求合并是什么玩意。


请求合并


现在我们抛开秒杀这个场景。

换一个更加合适,大家可能更容易理解的场景来聊聊什么是请求合并。

就是热点账户。

什么是热点账户呢?

在第三方支付系统或者银行这类交易机构中,每产生一笔转入或者转出的交易,就需要对交易涉及的账户进行记账操作。

记账一般来说涉及到两个部分。

  • 交易系统记录这一笔交易的信息。
  • 账户系统需要增加或减少对应的账户余额。

如果对于某个账户操作非常的频繁,那么当我们对账户余额进行操作的时候,就会涉及到并发处理的问题。

并发了怎么办?

是的,我们可以对账户进行加锁处理。这样一来,这个账户就涉及到频繁的加锁解锁操作。

这样我们可以保证数据不出问题,但是随之带来的问题是随着并发的提高,账户系统性能下降。

这个账户,就是热点账户,就是性能瓶颈点。

热点账户是业界的一个非常常见的问题。

我所了解到的常规解决方案大概可以分为三种:

  • 异步缓冲记账。
  • 设立影子账户。
  • 多笔合一记账。

本小节主要是介绍“多笔合一记账”解决方案,从而引出请求合并的概率。

对于另外两个解决方案,就先简单的说一下。

首先异步缓冲记账。

我先不解释,你就看着这个名字,想着这个场景,你觉得你会想到什么?

异步,是不是想到了 MQ?

那么请问你系统里面为什么要引入 MQ 呢?

来,面试八股文背起来:异步处理、系统解耦、削峰填谷。

你说我们当前的这个场景下属于哪一种情况?

肯定是为了做削峰填谷呀。

假设账务系统的 TPS 是 200 笔每秒,当请求低于 200 笔每秒的时候,账务服务基本上能够及时处理马上返回。

从用户的角度来说就是:啪的一下,很快啊。我就收到了记账成功的通知了,也看到账户余额发生了变化。

但是在业务高峰期的时候,流量直接翻倍,每秒过来了 400 笔请求,这个时候对于账务系统来说就是流量洪峰,需要进行削峰了,队列里面开始堆积着请求,开始排队处理了。

在流量低谷的时候,就可以把这部分数据消费完成。

相当于数据扔到队列里面之后,就可以告诉用户记账成功了,钱马上就到。

但是这个方案带来的问题也是很明显的,如果流量真的爆了,一天都没有谷让你填,队列里面堆积着大量的请求还没来得及处理,你怎么办?

这对于用户而言就是:你明明告诉我记账成功了,为什么我的账户余额迟迟没有变化呢?是不是想阴我钱,我反手就是一波投诉。

另外一个风险点就是对于支出类的请求,如果被削峰,很明显,我们提前就告诉了用户操作成功,但是真正动账户余额的时候已经延迟了,所以可能会出现账户透支的情况。

另外一个设立影子账户的方案,其实和我们本次的请求合并的主题是另外一个不同的方向。

它的思想是拆分。

热点账户说到底还是一个单点问题,那么对于单点问题,我们用微服务的思想去解决的话是什么方案?

就是拆分。

假设这个热点账户上有 100w,我设立 10 个影子账户,每个账户 10w ,那么是不是我们的流量就分散了?从一个账户变成了 10 个账户。

压力也就进行了分摊。

这个方案就有点类似于秒杀场景中的库存了,库存我们也可以拆多份。

但是带来的问题也很明显。

一是获取账户余额的时候需要进行汇总操作。

二是假设用户要扣 11w 呢?我们总余额是够的,但是每个影子账户上的钱是不够的。

三是你的影子账户选择的算法是很重要的,是用随机?轮训?加权?这些对于账务成功率都是有比较大的影响的。

另外这个思想,我在之前的文章中也提到过,有兴趣的可以看看其在 JDK 源码中的应用:我从LongAdder中窥探到了高并发的秘籍,上面只写了两个字...

好了,回到本次的主题:多笔合一笔记账。

有个网红店,生意非常的好,每天很多人在店里面消费。

当用户扫码支付后,请求会发送到这个店对接的第三方支付公司。

当支付公司收到请求,并完成记账操作后才会告知商户用户支付成功。可以给用户商品了。


image.png


随着店里生意越来越好,带来的问题是第三方支付公司的系统压力增加,扛不住这么大的并发了。导致用户支付成功率的下降或者用户支付成功后很长时间才通知到商户。

那么针对这个商户的账户,我们就可以做多笔合一笔处理。

当记录进入缓冲流水记录表之后,我们就可以通知商户用户支付成功了,至于钱,你放心,我有定时任务,一会就到账:


image.png


所以当用户下单之后,我们只是先记录数据,并不去实际动账户。等着定时任务去触发记账,进行多笔合并一笔的操作。

比如下面的这个示意图:


image.png


商户实际有 5 个用户支付记录,但是这 5 笔记录对应着一条账户流水。我们拿着账户流水,也是可以追溯到这 5 笔交易记录的。

这样的好处是吞吐量上来了,通知及时,用户体验也好了。但是带来的弊端是余额并不是一个准确的值。

假设我们的定时任务是一小时汇总一次,那么商户在后端看到的交易金额可能是一小时之前的数据。

而且这种方案对于账户收钱的场景非常的适合,但是减钱的场景,也是有可能会出现金额为负的情况。

不知道你有没有看出多笔合一笔处理方案的秘密。

如果我们把缓冲流水记录表看作是一个队列。那么这个方案抽象出来就是队列加上定时任务。

所以,请求合并的关键点也是队列加上定时任务

文章看到现在,请求合并我们应该是大概的了解到了,也确实是有真实的应用场景。

除了我上面的例子外,比如还有 redis里面的 mget,数据库里面的批量插入,这玩意不就是一个请求合并的真实场景吗?

比如 redis 把多个 get 合并起来,然后调用 mget。多次请求合并成一次请求,节约的是网络传输时间。

还有真实的案例是转账的场景,有的转账渠道是按次收费的,那么作为第三方公司,我们就可以把用户的请求先放到表里记录着,等一小时之后,一起汇总发起,假设这一小时内发生了 10 次转账,那么 10 次收费就变成了 1 次收费,虽然让客户等的稍微久了点,但还是在可以接受的范围内,这操作节约的就是真金白银了。

目录
相关文章
|
4月前
|
缓存 前端开发 中间件
[go 面试] 前端请求到后端API的中间件流程解析
[go 面试] 前端请求到后端API的中间件流程解析
|
2月前
|
缓存 负载均衡 API
抖音抖店API请求获取宝贝详情数据、原价、销量、主图等参数可支持高并发调用接入演示
这是一个使用Python编写的示例代码,用于从抖音抖店API获取商品详情,包括原价、销量和主图等信息。示例展示了如何构建请求、处理响应及提取所需数据。针对高并发场景,建议采用缓存、限流、负载均衡、异步处理及代码优化等策略,以提升性能和稳定性。
|
2月前
|
缓存 算法 架构师
京东面试:如何设计600Wqps高并发ID?如何解决时钟回拨问题?
资深架构师尼恩在其读者交流群中分享了关于分布式ID系统的设计与实现,特别是针对高并发场景下的解决方案。他强调了分布式ID系统在高并发核心组件中的重要性,并详细介绍了百度的UidGenerator,这是一个基于Snowflake算法改进的Java实现,旨在解决分布式系统中的唯一ID生成问题。UidGenerator通过自定义workerId位数和初始化策略,支持虚拟化环境下的实例自动重启和漂移,其单机QPS可达600万。此外尼恩的技术分享不仅有助于提升面试表现,还能帮助开发者在实际项目中应对高并发挑战。
京东面试:如何设计600Wqps高并发ID?如何解决时钟回拨问题?
|
4月前
|
JavaScript 前端开发 Java
面试官:假如有几十个请求,如何去控制并发?
面试官:假如有几十个请求,如何去控制并发?
|
5月前
|
监控 网络协议 Java
Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
76 0
|
5月前
|
设计模式 安全 NoSQL
Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
72 0
|
5月前
|
设计模式 安全 Java
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
68 0
|
5月前
|
设计模式 存储 缓存
Java面试题:结合建造者模式与内存优化,设计一个可扩展的高性能对象创建框架?利用多线程工具类与并发框架,实现一个高并发的分布式任务调度系统?设计一个高性能的实时事件通知系统
Java面试题:结合建造者模式与内存优化,设计一个可扩展的高性能对象创建框架?利用多线程工具类与并发框架,实现一个高并发的分布式任务调度系统?设计一个高性能的实时事件通知系统
59 0
|
5月前
|
存储 安全 Java
Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
71 0
|
5月前
|
并行计算 安全 算法
Java面试题:Java内存管理与多线程并发处理,设计一个Java应用,该应用需要处理大量并发用户请求,同时要求对内存使用进行优化,如何通过垃圾回收机制优化内存使用?
Java面试题:Java内存管理与多线程并发处理,设计一个Java应用,该应用需要处理大量并发用户请求,同时要求对内存使用进行优化,如何通过垃圾回收机制优化内存使用?
43 0