当前位置:首页 > 问答 > 正文

Redis 幂等性 利用Redis保障操作幂等性,提升系统安全

Redis实战:用Redis保障操作幂等性,让系统更安全

场景引入:重复支付的烦恼

想象一下这个场景:你在电商平台抢购限量球鞋,点击"立即支付"后页面突然卡住,心急如焚的你连点三次,结果收到三条银行扣款短信——这不是段子,而是某平台去年"双十一"真实发生的故障,这种因重复操作导致的问题,本质上就是系统缺乏幂等性保障。

今天我们就来聊聊,如何用Redis这把"瑞士军刀",轻松解决这个让程序员头疼的幂等性问题。


什么是幂等性?

同样的操作执行一次或多次,结果完全相同,就像家里的电灯开关,按一次开,再按一次关,无论按多少次效果都确定。

在系统中,这些操作必须保证幂等性:

  • 支付接口(重复支付会出大事)
  • 订单创建(避免生成重复订单)
  • 短信发送(用户不想收10条验证码)

Redis实现幂等性的三大绝招

令牌桶防重(适合前端交互)

原理:每次操作前先领"一次性门票"

Redis 幂等性 利用Redis保障操作幂等性,提升系统安全

// 生成令牌(存Redis并设置过期时间)
String token = UUID.randomUUID().toString();
redisTemplate.opsForValue().set("order:token:"+userId, token, 5, TimeUnit.MINUTES);
// 处理请求时校验
String storedToken = redisTemplate.opsForValue().get("order:token:"+userId);
if(token.equals(storedToken)){
    redisTemplate.delete("order:token:"+userId); // 用后即焚
    // 处理业务逻辑...
}

适用场景:防止表单重复提交、秒杀按钮连点


唯一键拦截(适合后端API)

原理:用业务唯一标识(如订单ID)作为Redis锁

def process_order(order_id):
    # 尝试设置NX锁(存在则设置失败)
    lock_key = f"order_lock:{order_id}"
    if not redis.setnx(lock_key, 1):  
        raise Exception("请勿重复操作")
    try:
        redis.expire(lock_key, 30)  # 防止死锁
        # 真正的业务处理...
    finally:
        redis.delete(lock_key)  # 释放锁

优化技巧

  • 加上过期时间避免死锁(建议用SETNX+EXPIRE原子操作)
  • 对高并发场景可增加随机退避重试

状态机校验(适合复杂流程)

原理:用Redis记录操作状态

Redis 幂等性 利用Redis保障操作幂等性,提升系统安全

func refundProcess(refundNo string) error {
    stateKey := "refund:state:" + refundNo
    // 原子性状态检查(Lua脚本保证原子性)
    script := `
        local current = redis.call('GET', KEYS[1])
        if current == 'PROCESSING' then
            return 0
        end
        redis.call('SET', KEYS[1], 'PROCESSING', 'EX', 60)
        return 1
    `
    allowed := redis.Eval(script, []string{stateKey}).Int()
    if allowed == 0 {
        return errors.New("操作正在处理中")
    }
    defer redis.Set(stateKey, "DONE", 10*time.Minute)
    // 执行退款逻辑...
}

适用场景:退款、审核等多步骤流程


实战避坑指南

  1. 防雪崩:所有Redis操作必须设置超时时间,避免故障时永久阻塞
  2. 防误删:删除Key前先校验Value(防止误删其他请求的锁)
  3. 监控报警:对高频失败的幂等校验要设置监控(可能是攻击征兆)
  4. 降级方案:Redis不可用时考虑本地缓存/Database降级

为什么选择Redis?

相比数据库方案,Redis有三大优势:

  • 性能:10万+ QPS的校验能力
  • 原子性:SETNX等命令天然支持原子操作
  • 丰富数据结构:String/Hash/Set都能玩出花样

幂等性不是可选功能,而是系统稳定的生命线,下次当你设计关键接口时,不妨问问自己:

"如果这个请求被重复发送10次,我的系统会爆炸吗?"

Redis 幂等性 利用Redis保障操作幂等性,提升系统安全

用Redis构建幂等防护网,可能只需要20行代码,但换来的将是安稳的睡眠和不再夺命连环Call的客服同事,毕竟,在分布式系统的世界里,宁可多验十次,不可错放一回

发表评论