Bootstrap

某顶级投行交易系统毫秒级交易防抖设计:基于Lua+Redis原子锁与Spring AOP的高频请求拦截实战

拉到最后👉👉👉: 一句话总结

背景和痛点

在投行交易系统和风控系统中,防抖键会影响业务的系统性能和业务准确性。打个广告🤣,根据自定义的核心业务参数和指定的前缀结合,可以直接看这个解决方案根据业务前缀和自定义核心业务参数结合,在投行交易系统中进行高效防抖
但是针对一些需要高频低风险的场景、无法判断核心字段参数的场景,比如交易员报价的情况下, 以上的防抖解决方案就不够用了。
基于此,设计了第二套无脑高效防抖防抖方案:基于ServletPath+Token进行分布式锁防抖方案。

需求拆解

略略略, 请看这里根据业务前缀和自定义核心业务参数结合,在投行交易系统中进行高效防抖

设计思路

  1. 用分布式锁Redis
  2. 基于ServletPath+Token,设计分布式锁的key

上架构

在这里插入图片描述

和参数拼接方式分布式缓存防抖解决方案有什么区别❓

两种解决方案的区别

维度 根据ServletPath+Token分布式锁防抖解决方案 自定义Key分布式缓存防抖解决方案
防抖目标 针对的是同一个用户对同一个接口的访问 防止相同业务参数的重复提交(人工选择参数,可能判断不精确)
唯一性依据 接口路径+用户标识 业务核心参数(比如交易订单号等)
内存效率 Key长度固定(路径+Token通常<100字节) 长度可变(可能含长文本参数)
反欺诈能力 依赖Token 依赖参数组合
场景 API访问频率控制 (比如交易员提交股权报价请求) 交易订单防重提交

一句话总结

混合使用最好

技术实现难点

  1. 解锁的时候防抢占:使用lua脚本原子性

代码实现

1. 基础代码略

2. 技术实现难点

2.1 自定义lua脚本

if redis.call('GET', KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end

2.2 自定义分布式锁:包括加锁 解锁

注意这里因为需要使用lua脚本进行逻辑判断redis.call(‘GET’, KEYS[1]) == ARGV[1] ,所以在Redis template中的key和value的序列化器和反序列化器需要是一样的,所以这里使用的是StringRedisTemplate

@Component
@Slf4j
public class RedisDistributeLock {
   
    @Resource
    private StringRedisTemplate stringRedisTemplate; // 切换为序列化器,

    public boolean setLock(String key, String value, long expire) {
   
        Boolean isSuccess;
        try {
   
          
;