1. 项目背景与核心需求
最近帮朋友公司开发了一套演唱会票务系统,这个项目让我对高并发场景下的系统设计有了更深刻的理解。现代演出市场火爆异常,周杰伦、张学友这类顶流歌手开票时经常出现百万级用户同时在线抢票的情况。传统票务平台在这种流量冲击下经常崩溃,导致粉丝们怨声载道。
这套系统要解决三个核心痛点:
- 瞬时百万级QPS的流量冲击
- 黄牛机器人的恶意刷票
- 票务库存的精准控制
我选择SpringBoot作为技术底座,配合Redis、RabbitMQ等中间件,最终实现了单机3000+ TPS的处理能力。下面分享具体实现方案和踩坑经验。
2. 系统架构设计
2.1 技术栈选型
后端框架:
- SpringBoot 2.7 + SpringMVC
- 选择理由:快速构建RESTful API,完善的生态组件
数据层:
- MySQL 8.0(InnoDB集群)
- Redis 7.0(Cluster模式)
- 组合原因:MySQL保证数据持久化,Redis应对高并发查询
中间件:
- RabbitMQ 3.11(消息队列)
- Redisson 3.18(分布式锁)
- 作用:异步削峰和解耦系统组件
安全防护:
- 人机验证(滑块+短信)
- 行为分析(鼠标轨迹检测)
- 目标:识别并拦截90%以上的黄牛请求
2.2 核心架构图
用户端 -> Nginx负载均衡 -> [API集群] ↓ [RabbitMQ] ↓ [库存服务] <-Redis锁-> [订单服务] -> [支付服务] ↓ MySQL集群关键设计原则:
- 读写分离:查询走Redis,写入走MySQL
- 异步处理:扣库存和生成订单通过消息队列解耦
- 无状态设计:方便水平扩展
3. 关键技术实现
3.1 库存控制方案
预扣库存设计:
// Redis Lua脚本保证原子性 String script = "if redis.call('exists',KEYS[1])==1 then\n" + " local stock = tonumber(redis.call('get',KEYS[1]))\n" + " if stock >= tonumber(ARGV[1]) then\n" + " return redis.call('decrby',KEYS[1],ARGV[1])\n" + " end\n" + " return -1\n" + "end\n" + "return -2";MySQL最终扣减:
UPDATE tickets SET stock = stock - 1 WHERE id = ? AND stock >= 1双重校验保证:
- Redis先做预扣减(应对高并发)
- MySQL最终扣减(保证数据准确)
3.2 分布式锁实现
采用Redisson的看门狗机制:
RLock lock = redissonClient.getLock("ticket:" + showId); try { if (lock.tryLock(3, 10, TimeUnit.SECONDS)) { // 处理核心业务 } } finally { lock.unlock(); }关键参数:
- waitTime: 3秒(获取锁等待时间)
- leaseTime: 10秒(锁自动释放时间)
3.3 消息队列设计
订单生成流程:
- 用户请求进入RabbitMQ队列
- 库存服务消费消息并扣减库存
- 生成订单数据写入MySQL
- 返回结果给用户
队列配置要点:
spring: rabbitmq: listener: simple: prefetch: 50 # 控制消费速率 concurrency: 10 # 消费者线程数4. 性能优化实践
4.1 缓存策略
多级缓存设计:
- 本地缓存(Caffeine):存储静态数据如场馆信息
- Redis集群:存储动态库存数据
- MySQL:持久化最终数据
缓存更新策略:
- 主动推送:库存变更时通过MQ通知各节点
- 被动失效:设置合理的TTL时间
4.2 接口优化
关键接口QPS对比:
| 优化措施 | 原QPS | 优化后QPS |
|---|---|---|
| 无缓存 | 120 | - |
| 添加Redis | - | 2500 |
| 增加本地缓存 | - | 3800 |
| Lua脚本优化 | - | 4200 |
4.3 压测数据
JMeter测试结果(4C8G服务器):
- 单节点最高承受3280 TPS
- 平均响应时间<200ms
- 错误率<0.1%
5. 防黄牛策略
5.1 人机验证方案
分级验证机制:
- 首次请求:滑块验证
- 高频请求:短信验证码
- 异常行为:语音验证+人工审核
5.2 行为特征分析
采集维度:
- 鼠标移动轨迹
- 点击间隔时间
- 页面停留时长
识别模型:
# 使用XGBoost分类器 clf = xgb.XGBClassifier( max_depth=5, learning_rate=0.1, n_estimators=100 )5.3 黑产对抗数据
实际运行效果:
- 拦截异常请求占比:87.6%
- 误杀正常用户:<0.5%
- 黄牛成功下单率:<0.01%
6. 踩坑经验总结
6.1 库存超卖问题
事故现象:某次压力测试时出现库存负数
根本原因:Redis和MySQL数据不一致
解决方案:
- 引入定时对账任务
- 增加数据库唯一约束
- 实现自动补偿机制
6.2 消息堆积问题
故障场景:支付服务宕机导致订单积压
**应对策略:
- 设置队列最大长度
- 实现死信队列
- 增加消费者监控
6.3 缓存雪崩预防
防护措施:
- 差异化过期时间
- 实现熔断降级
- 热点数据永不过期
7. 部署方案
7.1 服务器配置
生产环境建议:
- API服务器:8C16G * 10台(K8S集群)
- Redis:16G内存 * 6节点(3主3从)
- MySQL:32C64G * 3台(主从架构)
7.2 监控体系
必备监控项:
- Prometheus:系统指标采集
- Grafana:可视化仪表盘
- ELK:日志分析
关键报警阈值:
- CPU使用率>70%持续5分钟
- Redis内存>80%
- MySQL连接数>90%
8. 扩展优化方向
- 动态扩容方案:基于K8S的HPA自动伸缩
- 多地域部署:通过DNS实现就近访问
- 智能风控升级:引入机器学习模型
- 预售系统:支持选座和连座购买
这个项目让我深刻体会到,高并发系统设计必须考虑完整的闭环:从流量接入、业务处理到数据存储,每个环节都需要针对性优化。特别提醒注意Redis持久化配置,我们曾因AOF配置不当导致数据丢失。建议采用RDB+AOF混合模式,并定期进行灾备演练。