本文章仅供个人学习使用。
架构层面
红包系统流量特点:整体并发流量巨大,对于单体红包流量不是很大。
什么意思?
- 秒杀系统:几百万人可能都盯着某个热点门票 or 商品,单一商品的瞬时并发量高。
- 红包系统:微信一个群就500人,单一红包瞬时流量不算高。但是同一时刻,有上百万的微信群在抢红包,整体流量很大。
1. 水平扩展
正因为如此,红包系统水平扩展比较容易,因为可以让一台机器处理一定范围的红包,不同红包之间的状态不会互相影响。

2. SET化
我们还可以在这个基础上更进一步,做「硬件资源隔离」或者叫「SET化」,为什么要这么干,原因有2个:
- 一、如果多个红包服务共享Redis、MySQL,虽然通过分片分摊了流量,但是Redis、MySQL要维护大量的TCP连接,数据库连接数可能被打满。
- 二、多个红包服务同时命中一个MySQL分片,事务冲突加剧。
所谓的SET化,或者说硬件资源隔离,就是给每个服务都配备独立的完整的硬件资源(数据库、中间件等),让每个服务可以独立部署。通过部署多套服务,来缓解上述2个问题。

数据库表设计
SQL
-- 红包订单表
CREATE TABLE red_pack_order (
id BIGINT PRIMARY KEY,
owner_id BIGINT NOT NULL,
target_id BIGINT NOT NULL,
red_pack_type INT NOT NULL,
total_money BIGINT NOT NULL,
total_red_pack_num INT NOT NULL,
red_pack_order_status INT NOT NULL,
created TIMESTAMP NOT NULL,
modified TIMESTAMP NOT NULL
);
-- 红包表
CREATE TABLE red_pack (
id BIGINT PRIMARY KEY,
red_pack_order_id BIGINT,
owner_id BIGINT NOT NULL,
target_id BIGINT NOT NULL,
red_pack_type INT NOT NULL,
total_money BIGINT NOT NULL,
total_red_pack_num INT NOT NULL,
red_pack_status INT NOT NULL,
created TIMESTAMP NOT NULL,
modified TIMESTAMP NOT NULL
);
-- 红包流水表
CREATE TABLE red_pack_record (
id BIGINT NOT NULL PRIMARY KEY,
red_pack_id BIGINT NOT NULL,
money BIGINT NOT NULL,
owner_id BIGINT NOT NULL,
red_pack_record_status INT NOT NULL,
created TIMESTAMP NOT NULL,
modified TIMESTAMP NOT NULL
);
业务层面
1. 发红包流程
- 用户填写红包信息,包括:总金额、拼手气还是固定金额、红包个数、标题、封面。
- 创建订单(向「红包订单表」中插入一条记录)。
- 启动定时任务:过期未付款取消订单。
- 调用支付接口。
- 接收到支付接口回调后,创建红包(向「红包表」中插入一条数据)同时,为了把扣减库存的操作上移到缓存,我需要同步Redis。
red_packet:{id}:remain_amount
red_packet:{id}:remain_count
- 调用消息系统推送消息的接口,把红包发送到目标(人 or 群)。
- 启动定时任务:红包过期对账、退款。
红包状态流转:已创建 -- 已支付 -- 已生效 -- 已抢完 -- 已过期
2. 抢红包流程
- 校验用户资格(用户是否在群里,用户是否已经抢过红包)
- 校验红包状态
- 通过Lua脚本实现 扣减库存 扣减的余额,在Redis中执行原子性的扣减。
- 记录红包流水(向红包流水表中写入一条记录)
- 通过消息队列 异步转账。
红包分配算法
两个大的方向:实时计算 和 预先生成
1. 二倍均值法
用户可以抢到的金额在 0.01元 和 2倍的均值之间。 如果剩余红包数为1,则用户直接带走全部余额。