高并发下合并接口请求
来源:互联网 发布:淘宝卖家漏发货不承认 编辑:程序博客网 时间:2024/06/04 18:36
在有一次对商品详情页进行压力测试时,因为商详页的数据来源非常多,经过的服务多,调用链很长,所以查询数据库的次数也就非常多,数据库连接池很快就被用光,导致很多请求被阻塞,也导致应用整体线程数非常高。虽然通过增加数据库连接池大小可以缓解问题,并且可以通过压力测试,但这治标不治本。商详页中有很多查询已经做了缓存,但还是有些如促销、(活动)价格、库存等是不能缓存(或是不能缓存太长时间)。
虽然促销、价格、库存等对实时性要求较高,数据可能变化频繁,但同一个商品的信息在同一时刻的信息应该是基本一致。数据实时性相差个几十毫秒上百毫秒对于用户来说是无感知。可以把和用户有关联的操作(如记录浏览历史)拆分开来,比如在接口层里先调用查询商品信息,查询到了之后再调用记录浏览历史等操作。
查询商品信息的时候,如果同一商品同一时刻有100个请求,那么其中的99次查询是多余的,可以把100个请求合并成一个真实的后台接口调用,只要控制好线程安全即可。我的想法是使用并发计数器来实现再配合本地缓存,计数器可直接用JDK提供的AtomicInteger,线程安全又提供原子操作。
以获取商品信息为例,每个商品id对应一个计数器,计数器初始值默认是0,当一个请求过来后通过incrementAndGet使计数器自增1并返回自增后的值。当该值等于1,表明该线程在这个时间点上是第一个到达的线程,然后就去调用真实的业务逻辑,在查询到结果后放入到本地缓存中。当该值大于1的时候,表明之前已有线程正在调用业务逻辑,则进入等待状态,并循环的查询本地缓存中是否已有数据可用。获取到结果后都调用decrementAndGet使计数器减1,计数器被减到0的时候就回到了初始状态,并且当减到0(代表最后一个线程)时清除缓存。
此方案有个数据延迟的地方,就是每次循环时的等待状态的时间。因为一次包含多次查库的业务调用,耗时基本都在几十毫秒,甚至是上百毫秒,可以把该等待睡眠设置小一点,比如10毫秒。这样即不会浪费CPU时间,实时性也比较高,但然也可以通过主动唤醒等待线程的方式,这个操作起来就比较复杂些。在这其中还可以添加一些异常处理、超时控制、最大重试次数,最大并发数(超时最大并发数就快速失败)等。
-----------------------------
附上相关代码实现(Github):synchplay/easyJCommon
- 高并发下合并接口请求
- 高并发下接口的并发问题
- 模拟高并发请求
- 高并发下PHP请求Redis异常处理
- 高并发下PHP请求Redis异常处理
- 高并发情况下 如何支撑大量的请求
- 高并发下接口核心业务方法限流
- PHP_curl模拟高并发请求
- java模拟高并发请求
- 高并发接口压测
- 高并发接口压测
- 利用redis缓存解决高并发下后端重复请求措施
- 高并发下CURL请求缓慢原因及解决方…
- 利用redis缓存解决高并发下后端重复请求措施
- httpclient 多线程高并发Get请求
- ajax异步请求高并发处理
- 手写高并发网络请求框架
- Redis和请求队列解决高并发
- OKHttp3学习笔记-Http Get请求
- 树莓派上运行docker
- 关于Linux下文件后缀名和文件的关系
- element.getTextContent()报错
- Java Scanner 类
- 高并发下合并接口请求
- 日期转换
- js修改title
- Tensorflow08-卷积神经网络
- 关于测试的面试题(登录功能测试)
- Java Socket 编程原理及教程
- 关于Object被Destroy之后,该Object的原引用==null的问题
- Activity 生命周期
- IL2CPP是什么?有了Mono为什么还需要IL2CPP?