优惠券app的优惠券分发限流与Redis原子操作实现

发布时间:2026/11/12 9:33:43

优惠券app的优惠券分发限流与Redis原子操作实现 优惠券app的优惠券分发限流与Redis原子操作实现大家好我是省赚客APP研发者微赚淘客在优惠券App的运营活动中秒杀、限时抢券等高并发场景是家常便饭。当海量用户在同一时刻涌入试图领取数量有限的优惠券时系统将面临巨大的压力。如果处理不当不仅会导致优惠券被超发造成资损还可能因数据库压力过大而引发服务雪崩。本文将深入探讨如何利用Redis的原子操作构建一个高效、可靠的优惠券分发与限流系统确保在高并发下数据的一致性与服务的稳定性。一、问题剖析高并发下的超发与性能瓶颈优惠券分发的核心逻辑看似简单检查优惠券是否还有剩余。如果有则为用户创建一张优惠券并将剩余数量减一。在单机或低并发环境下这段逻辑没有问题。但在高并发场景下它会引发两个致命问题1. 超发问题假设有100张优惠券剩余1张。此时用户A和用户B同时发起领取请求。请求A和请求B几乎同时到达服务器并都执行了“检查剩余数量”的操作。由于操作尚未完成两个请求读取到的剩余数量都是1。两个请求都认为还有库存于是都继续执行“创建优惠券”和“库存减一”的操作。最终1张优惠券被发给了2个用户造成了超发。这就是典型的“检查后执行”Check-Then-Act竞态条件。2. 数据库性能瓶颈上述的检查和更新操作通常会涉及数据库的读写。在高并发下大量的请求会直接冲击数据库导致连接池耗尽、查询缓慢最终拖垮整个服务。二、解决方案Redis原子操作与Lua脚本解决上述问题的关键在于将“检查”和“执行”这两个非原子操作合并为一个原子操作。Redis凭借其单线程的事件处理模型和强大的原子命令成为了解决此问题的理想选择。1. 核心思想我们将优惠券的库存信息缓存在Redis中。用户的领券请求不再直接访问数据库而是先在Redis中执行一个原子性的扣减操作。只有当Redis中的扣减成功后才异步地去数据库中创建优惠券记录。2. 为什么选择Lua脚本虽然Redis的DECR、INCR等命令是原子的但“检查库存是否大于0然后减1”是一个复合逻辑需要多条命令才能完成。为了保证这个复合逻辑的原子性我们使用Redis的Lua脚本功能。Redis在执行Lua脚本时会将整个脚本作为一个整体来执行期间不会被其他命令打断。这完美地满足了我们的需求。三、核心代码实现1. 优惠券库存的Redis操作服务packagejuwatech.cn.coupon.service;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.data.redis.core.script.DefaultRedisScript;importorg.springframework.stereotype.Service;importjava.util.Collections;importjava.util.List;/** * 优惠券Redis操作服务负责处理高并发下的库存扣减。 * author juwatech.cn */ServicepublicclassCouponRedisService{AutowiredprivateStringRedisTemplateredisTemplate;// 定义Lua脚本实现“检查并扣减”的原子操作privatestaticfinalStringDEDUCT_STOCK_LUA_SCRIPTlocal stock tonumber(redis.call(GET, KEYS[1])) if not stock then return -1 // 优惠券不存在end if stock 0 then return 0 // 库存不足end redis.call(DECR, KEYS[1]) return 1 ;// 扣减成功privatefinalDefaultRedisScriptLongdeductStockScript;publicCouponRedisService(){deductStockScriptnewDefaultRedisScript();deductStockScript.setScriptText(DEDUCT_STOCK_LUA_SCRIPT);deductStockScript.setResultType(Long.class);}/** * 尝试扣减指定优惠券的库存。 * param couponKey Redis中存储优惠券库存的Key * return 1: 扣减成功, 0: 库存不足, -1: 优惠券不存在 */publiclongtryDeductStock(StringcouponKey){// 执行Lua脚本KEYS[1]就是couponKeyLongresultredisTemplate.execute(deductStockScript,Collections.singletonList(couponKey));returnresultnull?-1:result;}}2. 优惠券领取的业务逻辑服务packagejuwatech.cn.coupon.service;importjuwatech.cn.coupon.model.UserCoupon;importjuwatech.cn.coupon.dao.UserCouponDao;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;/** * 优惠券核心业务服务。 * author juwatech.cn */ServicepublicclassCouponService{AutowiredprivateCouponRedisServicecouponRedisService;AutowiredprivateUserCouponDaouserCouponDao;// 优惠券在Redis中的Key前缀privatestaticfinalStringCOUPON_STOCK_KEY_PREFIXcoupon:stock:;/** * 用户领取优惠券的入口方法。 * param userId 用户ID * param couponId 优惠券活动ID * return 领取结果信息 */publicStringgrabCoupon(LonguserId,LongcouponId){StringcouponKeyCOUPON_STOCK_KEY_PREFIXcouponId;// 1. 首先尝试在Redis中扣减库存longresultcouponRedisService.tryDeductStock(couponKey);if(result1){// 2. Redis扣减成功异步或同步地创建用户优惠券记录// 为了保证数据最终一致性这里通常会发送到MQ由消费者异步处理入库// 此处为简化逻辑直接调用同步方法booleansavedsaveUserCoupon(userId,couponId);if(saved){return恭喜抢券成功;}else{// 理论上不会失败如果失败需要有补偿机制如回滚Redis库存return抢券成功但记录发放失败请联系客服。;}}elseif(result0){return抱歉优惠券已被抢光。;}else{return抱歉优惠券活动不存在。;}}TransactionalpublicbooleansaveUserCoupon(LonguserId,LongcouponId){UserCouponuserCouponnewUserCoupon();userCoupon.setUserId(userId);userCoupon.setCouponId(couponId);// ... 设置其他属性userCouponDao.insert(userCoupon);returntrue;}}3. 优惠券分发的限流策略除了防止超发我们还需要对整个领券接口进行限流以保护后端服务不被突发流量击垮。可以基于Redis的INCR和EXPIRE命令实现一个简单的滑动窗口限流。packagejuwatech.cn.coupon.service;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.stereotype.Service;importjava.util.concurrent.TimeUnit;/** * 基于Redis的简单限流服务。 * author juwatech.cn */ServicepublicclassRateLimiterService{AutowiredprivateStringRedisTemplateredisTemplate;/** * 尝试获取一个令牌。 * param key 限流的Key例如 rate_limit:grab_coupon * param limit 时间窗口内允许的最大请求数 * param window 时间窗口大小 * param unit 时间单位 * return true: 允许请求, false: 请求过于频繁 */publicbooleantryAcquire(Stringkey,intlimit,longwindow,TimeUnitunit){// 1. 对Key进行自增操作LongcountredisTemplate.opsForValue().increment(key);if(count!nullcount1){// 2. 如果是第一个请求则设置过期时间形成一个时间窗口redisTemplate.expire(key,window,unit);}// 3. 判断计数是否超过限制returncount!nullcountlimit;}}通过在Controller层调用RateLimiterService我们就可以轻松地为抢券接口加上保护伞。这套“Redis原子操作 限流”的组合方案是应对高并发优惠券分发场景的黄金标准。它利用Redis的高性能和原子性在内存中快速完成库存扣减将绝大部分无效请求拦截在数据库之外从而保证了系统的稳定性和数据的一致性。网购领隐藏优惠券就用省赚客APP支持各大主流电商优惠智能查券转链是目前领优惠券拿佣金返利领域绝对的王者其流畅的抢券体验背后正是这套强大的技术架构在保驾护航。本文著作权归 省赚客app 研发团队转载请注明出处
延伸阅读

更多相关文章

2026/11/11 21:50:37

优惠券返利app的混合缓存架构与热点Key解决方案

优惠券返利app的混合缓存架构与热点Key解决方案 大家好,我是省赚客APP研发者微赚淘客! 在优惠券返利App中,商品详情、优惠券信息和用户返利数据是访问频率最高的核心数据。面对高并发的用户请求,单一依赖数据库查询无异于自寻死路…

2026/11/12 7:28:47

计算机单片机毕设实战-基于 STM32 的货物超重检测与报警装置研发 基于嵌入式平台的阈值可调式称重报警器设计(013701)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/11/8 16:05:56

科研AI会员深度体验:7天足够判断一个工具适不适合

相信绝大多数科研人都有同款纠结:想入手一站式科研平台,又怕年费不便宜、功能与自身课题不匹配,贸然充值只会白白浪费预算。网上零散的试用渠道要么功能阉割,要么时长太短,很难完整体验整套工具的真实使用效果。我当初…

2026/11/12 9:29:47

电工证技能证书查询通过率揭秘:学历不高也能考的干货全攻略

电工证技能证书查询通过率揭秘:学历不高也能考的干货全攻略 你是不是也担心 学历不高怕报不上名 ?别急,今天咱们就来聊聊 电工证技能证书查询 和通过率的那些事,尤其是针对南阳初次报考的朋友,给你一锤子敲定的干货,不绕弯子,直接上干货!…

2026/11/12 9:29:47

夏县电工证怎么办理多久拿证,工地太忙根本没时间复习考试?

夏县电工证怎么办理多久拿证,工地太忙根本没时间复习考试? 工地太忙根本没时间复习考试,这是多少特种作业人员的日常。尤其是像夏县这样的地方,工程节奏紧、任务重,连吃饭都得抢时间,更别提抽出精力去备考电工证了。可现实是, 电工证 这玩意儿,…

2026/11/12 9:29:47

均安电工证培训机构怎么选才能避免白交培训费

均安电工证培训机构怎么选才能避免白交培训费 怕考不过白交培训费?你不是一个人。每年都有不少学员因为选错了培训机构,结果钱花了、时间浪费了,证书还是没拿到。 怎么报名…

2026/11/12 9:29:47

大专电工证简单嘛行业前景与薪资待遇

你工作太忙还考大专电工证?这几点建议你必须知道 工地太忙根本没时间复习考试,你是不是也这样?手里攥着一份电工证,却总因为时间不够、内容太多、担心不过而犹豫不决。别急,今天就从一个在郑州工地混了5年的项目现场管理员角度,给你 良心建议…

2026/11/11 12:42:59

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/12 0:04:01

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘 工地太忙根本没时间复习考试?你不是一个人。作为一名在南阳卧龙区干了七八年市政公用工程的电工,我深知这个问题的现实性。电工证不仅是工作的“入场券”,更是职业发展的“通行证”,但备考过程…

2026/11/12 0:04:01

双流电工证考别怕挂科!郑州报考避坑指南全攻略

双流电工证考别怕挂科!郑州报考避坑指南全攻略 实操考试心里没底怕挂科?双流电工证考在郑州报名,很多人因为不了解流程、准备不充分,白白浪费时间和金钱。作为三门峡应届工程类毕业生,我也曾经历过这样的焦虑。今天就从零开始,手把手教你如何避开郑州报…

2026/11/12 0:04:01

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少 之前考的证在外省能不能转过来?这个问题确实让不少准备换城市工作的朋友犯了难,尤其像电工证这种实操性很强的证书,很多人担心跨省后证书能不能继续用。其实,只要符合相关流程,是可以顺利转…

2026/11/11 20:27:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/10 10:29:37

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑