版本说明
本文源码分析基于 Redisson 3.24.3,文中 Lua 脚本与结论均以该版本为准;涉及历史行为对比时另行标注版本号。
核心设计
Redisson 的 RRateLimiter 采用"发放记账、到期回收"的滑动窗口模型,状态拆成三个 Redis 结构(以 key 为 mykey、60 秒放行 1 次、OVERALL 模式为例):
版本说明
本文源码分析基于 Redisson 3.24.3,文中 Lua 脚本与结论均以该版本为准;涉及历史行为对比时另行标注版本号。
Redisson 的 RRateLimiter 采用"发放记账、到期回收"的滑动窗口模型,状态拆成三个 Redis 结构(以 key 为 mykey、60 秒放行 1 次、OVERALL 模式为例):
在线支付业务中,经常会遇到掉单问题:用户已完成支付,但订单状态仍显示"待付款"。通常,用户支付完成后,第三方支付平台会通过梯度通知机制向商户同步支付结果。然而,若支付平台因网络波动、系统故障等原因导致通知失败,就需要引入补偿机制——比如:通过定时任务每隔一段时间主动查询特定时段内的待支付订单,批量发送至第三方支付平台查询支付结果,并同步更新系统订单状态,通知下游服务。为了高效处理这类订单,通常会借助线程池实现并发处理。
Q:定时任务多久查一次?
A:假设用户通常在5分钟内完成支付,那么定时任务每隔5分钟查询一次。
Q:每次查询的时间跨度是多少?
A:查一天前到5分钟前待支付的订单。
Q:每次查询出的待支付订单期望多久时间处理完?
A:每批订单期望1分钟内处理完。
Q:平时和大促期间,单位时间内大约发生多少次掉单情况?
A:平时每5分钟大约掉单1200次,大促期间每5分钟大约5000次。
在 Java 服务端开发中,线程池几乎无处不在。
异步任务、接口聚合、批量处理、消息消费、第三方 RPC...只要一个任务不希望直接占用当前线程太久,我们往往都会想到线程池。
而线程池最让人头疼的问题之一,就是:
corePoolSize 到底应该设置多少?
maximumPoolSize 设置多少合适?
queueCapacity 到底应该设置 10、50,还是 1000?
M/M/c 是排队论(Queuing Theory)中最经典的多服务台模型:
M / M / c / ∞ / ∞
到达过程 / 服务时间 / 服务台数 / 队列容量 / 顾客总数
| 字母 | 含义 | 数学意义 |
|---|---|---|
| 第一个 M | Markovian 到达(无记忆) | 顾客到达服从 泊松分布,到达间隔时间相互独立、无记忆 |
| 第二个 M | Markovian 服务时间(无记忆) | 服务时间服从 指数分布,同样无记忆性 |
| c | 服务台数量 | c = 1 时退化为 M/M/1,c = ∞ 时退化为 M/M/∞ |
有人说:Redis 已经够快了,还加二级缓存做什么?
其实,二级缓存的主要目的不是为了让已经很快的接口变得更快,而是为了减轻 Redis 的压力,尤其是当系统面对脉冲型热点,或出现热 key 时,为了提升系统的稳定性,二级缓存就非常管用。
电商大促期间,某些商品会突然变得很热门,短时间内会有大量的用户同时频繁访问,如果你的商品详情接口未加二级缓存,那么这些请求会直接打到 Redis,造成 Redis 中热 key 的产生。
要知道 Redis 单实例 QPS 上限为 10万,如果某个 key 的 QPS 为 1万,那就占用了 10% 的实例处理能力,若该 key 的访问量继续激增,可能造成 Redis 单节点 CPU 和带宽瓶颈,进而导致实例上其他 key 的访问延迟。
据 Easy Excel 官网介绍:
EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。
16M内存23秒读取75M(46W行25列)的Excel(3.2.1+版本)
