抢红包流程图及问题记录

几十万级别并发的抢红包,抢优惠券方案

使用的组件

java redis

简介

场景抽象:有限资源下的大量并发请求。

核心的痛点有以下部分:

  1. 锁的原子性
  2. 避免死锁
  3. 锁竞争下的性能优化
  4. Redis脑裂时的可用性保障

流程如下

  1. 客户端发起抢购请求
  2. 生成唯一UID(用来做锁持有者的唯一标识,锁的释放也是基于这个标识来判断是否为当前用户持有,确保只能删除自己持有的锁)
  3. 后台使用set nx px获取保证原子性的锁
  4. 获取到锁竞争结果(成功/失败)。这个步骤使用lua脚本保证原子性
  5. 如果成功,那么操作资源(扣库存)。操作成功后,使用lua脚本转验然后删除锁。
  6. 如果失败,那么非阻塞重试。(接口做异步等待小时间,或者直接返回"抢购火爆,请稍后再试")防止线程阻塞。

问题点以及解决方案

  1. 锁的原子性
    当并发请求的时候,Redis的"获取锁"和"设置过期时间"应该是一个命令,否则分成两步,中间可能因为节点故障中断,导致锁没有过期时间,破坏原子性。
    当锁使用完毕后,Redis的"查询锁"和"删除锁"应该是一个命令,否则分成两步,可能会出现查询后锁过期,此时删除的是新客户端获取的锁。破环原子性。
    解决方案:
    加锁的时候,使用 SET key value NX PX 命令,例如: SET shoes:lock uuid-2334 NX PX 1000
    删除锁的时候使用lua脚本
  2. 死锁
    客户端获取锁以后,因程序崩溃、网络中断等原因,未主动释放锁,且锁未设置过期时间,导致锁一直被占用。
    释放锁时未做身份校验,误删其他客户端的锁,引发锁归属混乱,间接导致死锁。
  3. 锁竞争性能原因
    单锁键被十万级以上并发请求争抢,所有请求集中在一个Redis节点上,造成热点key,引发请求排队,响应延迟。
    阻塞式获取锁(循环重试)导致线程等待,浪费服务器资源,降低并发率。
  4. Redis脑裂导致锁失效
    主节点与从节点分区,从节点提升为新主节点,原主节点仍对外服务,此时两个主节点都能被获取锁,导致分布式锁失效,出现"锁冲突"。
相关推荐
金銀銅鐵31 分钟前
[Java] 如何理解 class 文件中字段的 access flags?
java·后端
小短腿的代码世界39 分钟前
Qt国际化深度解析:从源码到企业级多语言实践
java·数据库·qt
凌冰_1 小时前
IDEA 集成Claude Code
java·ide
SXJR1 小时前
Java中的Cross-Encoder模型解决方案
java·开发语言
彦为君1 小时前
JavaSE-11-BIO/NIO/AIO(多人聊天室)
java·开发语言·python·ai·nio
计算机安禾1 小时前
【c++面向对象编程】第43篇:可变参数模板(C++11):优雅处理不定长参数
java·开发语言·c++
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第69题】【JVM篇】第29题:GC Roots 有哪些?
java·开发语言·jvm·面试
William Dawson1 小时前
【通俗易懂!Spring四大核心注解源码解读:@Configuration、@ComponentScan、@Import、@EnableXXX实战】
java·后端·spring
Tigshop开源商城1 小时前
Tigshop 开源商城系统 JAVA v5.8.28 版本发布|『角色权限管理+店铺后台跳转逻辑』优化
java·开源商城系统·tigshop
彦为君2 小时前
JavaSE-10-并发编程(11个案例)
java·开发语言·python·ai·nio