开篇:
之前也看过一些相关的书籍,最近又在学习redis的相关知识,不过这次偏实战一些,花了几天时间做了一个抢红包的功能,把设计的思路以及最终的源码贴出来给大家分享一下,本人自己自测了一下,能非常清楚的支持10000以上的QPS,估计还能支持更高,(特别说明,这里要抛去数据库,因为数据库在插入的时候存在明显瓶颈,本人机器4核8G),压测是利用Jmeter读取脚本的形式进行压测,此次测试,源码,数据库,jmeter压测工具都在本人机器上。
功能设计:
新建红包:并发较小,建议先让数据进入缓存(redis),然后再进行持久化,注意考虑到两个动作的保证同一个事务,redis放入两个key,分别为:{key1:红包总金额},{key2,红包总数}。
抢红包:并发较大,主要操作的是redis,为了最大的发挥效能,本次注意是利用lua脚本进行操作,且能保证原子性。
拆红包:为本次功能的重点,拆红包,涉及到各种校验例如改用户是否已经抢过红包了,红包金额还剩下多少,红包总数还剩下多少,红包金额和红包总数是否能匹配上,特别是在大并发的情况下,如果保证数据的一致性。
表结构设计:
DROP TABLE IF EXISTS `red_packet_info`;
CREATE TABLE `red_packet_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`red_packet_id` bigint(11) NOT NULL DEFAULT '0' COMMENT '红包id,采用timestamp+5位随机数',
`total_amount` int(11) NOT NULL DEFAULT '0' COMMENT '红包总金额,单位分',
`total_packet` int(11) NOT NULL DEFAULT '0' COMMENT '红包总个数',
`remaining_amount` int(11) NOT NULL DEFAULT '0' COMMENT '剩余红包金额,单位分',
`remaining_packet` int(11) NOT NULL DEFAULT '0' COMMENT '剩余红包个数',
`uid` int(20) NOT NULL DEFAULT '0' COMMENT '新建红包用户的用户标识',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8mb4 COMMENT='红包信息表,新建一个红包插\r\n入一条记录';-- ----------------------------
-- Table structure for red_packet_record
-- ----------------------------
DROP TABLE IF EXISTS `red_packet_record`;
CREATE TABLE `red_packet_record` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`amount` int(11) NOT NULL DEFAULT '0' COMMENT '抢到红包的金额',
`nick_name` varchar(32) NOT NULL DEFAULT '0' COMMENT '抢到红包的用户的用户名',
`img_url` varchar(255) NOT NULL DEFAULT '0' COMMENT '抢到红包的用户的头像',
`uid` int(20) NOT NULL DEFAULT '0' COMMENT '抢到红包用户的用户标识',
`red_packet_id` bigint(11) NOT NULL DEFAULT '0' COMMENT '红包id,采用timestamp+5位随机\r\n数',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16448 DEFAULT CHARSET=utf8mb4 COMMENT='抢红包记录表,抢一个红包插\r\n入一条记录';
接口界面