日淘平台优惠券系统的设计:从规则引擎到防超领

日淘平台为了吸引用户,通常会提供多种优惠券功能 :新人券、运费券、满减券、节日券等。北极星日淘 的优惠券系统每天处理数万次领券和核销请求,必须保证高并发下的准确性和一致性。

本文将分享其技术架构。

一、优惠券的数据模型

CREATE TABLE `coupon` ( `id` bigint PRIMARY KEY AUTO_INCREMENT, `name` varchar(100) NOT NULL, `type` tinyint COMMENT '1:满减 2:折扣 3:运费减免', `threshold` int COMMENT '使用门槛(分)', `reduce_amount` int COMMENT '减免金额(分)', `total_quantity` int COMMENT '总发行量', `remain_quantity` int COMMENT '剩余数量', `per_user_limit` int DEFAULT 1 COMMENT '每人限领', `start_time` datetime, `end_time` datetime);

二、高并发领券:Redis 预扣库存

直接操作 MySQL 会导致行锁竞争。北极星日淘 使用 Redis + Lua 脚本实现原子性扣减。

-- 领券 Lua 脚本 local key = KEYS1 -- 优惠券库存 key local user_key = KEYS2 -- 用户已领 key local user_id = ARGV1local limit = tonumber(ARGV2)local user_count = redis.call('scard', user_key)if user_count >= limit then return -1 -- 超过限领数量 endlocal remain = redis.call('get', key)if not remain or tonumber(remain) <= 0 then return -2 -- 库存不足 endredis.call('decr', key)redis.call('sadd', user_key, user_id)return 1

三、规则引擎:动态匹配最优券

用户下单时,系统需要从多张可用券中自动选择最优惠的一张。北极星日淘 引入了 Drools 规则引擎。

rule "Auto choose best coupon" when order: Order(totalAmount \> 0) couponList: ArrayList(size > 0) from couponService.getAvailableCoupons(order) then Coupon best = null; for (Coupon c : couponList) { if (best == null || c.calcDiscount(order) \> best.calcDiscount(order)) { best = c; } } $order.setSelectedCoupon(best);end

四、防超领和作弊

为了防止用户恶意刷券,系统还做了以下限制:

同一用户 ID、同一设备指纹、同一 IP 在短时间内多次领券会被限流。使用 Sentinel 熔断降级,当领券 QPS 超过阈值时,自动返回兜底逻辑。

spring: cloud: sentinel: flow: - resource: "receiveCoupon" count: 100 grade: 1 # QPS 限流

五、总结

北极星日淘 的优惠券系统采用 Redis 预扣库存 + Lua 原子操作 + Drools 规则引擎 + Sentinel 限流,在高并发场景下稳定运行。这套设计可以复用到大多数电商平台的营销系统中。

对于后端开发者,尤其是电商系统开发者,这是一个非常经典的设计案例。

#优惠券功能 #规则引擎 #高并发 #北极星日淘

相关推荐
极小狐5 天前
MR 里测试摘要空白、覆盖率不显示?JUnit 与覆盖率配置 9 步排查
数据库·ci/cd·junit·单元测试·mr·devops·代码覆盖率
Best-Wishes6 天前
科来网络分析系统(技术交流版)使用说明书
开发语言·junit·php
贾宝玉的玉宝贾7 天前
FreeSWITCH 简单图形化界面 70 - 监听/密语的lua脚本
开发语言·junit·lua·voip·freeswitch·sip·ippbx
企业数字化笔记8 天前
多租户系统从哪里开始设计?租户身份、数据隔离、权限与套餐的整体方案
java·spring boot·后端·junit
众链网络12 天前
大客流票务系统怎么防超卖:库存并发、候补队列与幂等设计的工程取舍
junit·架构
深念Y15 天前
rime-雾凇拼音-配置记录
linux·junit·软件·拼音·kde
白山编程大哥18 天前
Lua 中使用 C 语言的用户自定义类型——userdata
c语言·junit·lua
行者游学20 天前
Kong 插件,解决2.5.1不支持原生暴露url
junit·kong
写后端的胖头鱼1 个月前
一文学会单元测试之----Junit
junit·单元测试
Java小白笔记1 个月前
Java 单元测试怎么写:JUnit 5、Mockito 与 Spring Boot 方法级实战
java·junit·单元测试