一、需求分析与系统定位
1.1 业务场景拆解
优惠券系统需支持三种核心场景:
- 实时发放:用户通过活动入口领取优惠券,需保证毫秒级响应(P99<500ms)
- 批量核销:订单支付时同步核销优惠券,需处理每秒数万次请求
- 数据统计:实时展示优惠券发放/使用数据,需支持每秒万级数据写入
典型业务指标要求:
- QPS峰值:10万+(大促期间)
- 数据一致性:99.99%
- 可用性:99.95%
- 响应延迟:P99<300ms
1.2 技术挑战分析
- 流量突增:促销活动期间流量可能暴涨10倍
- 数据一致性:分布式环境下保证优惠券状态准确
- 防刷机制:防止恶意用户批量领取
- 故障恢复:系统崩溃后30秒内恢复服务
二、系统架构设计
2.1 整体架构图
[用户请求] → [CDN] → [负载均衡] → [API网关] → [微服务集群]↓ ↓ ↓[缓存集群] [消息队列] [数据库集群]
2.2 核心模块设计
2.2.1 发放服务
- 无状态设计:使用JWT令牌实现会话管理
-
令牌桶算法:控制单个用户领取频率(示例代码):
public class TokenBucket {private final AtomicLong tokens;private final long capacity;private final long refillRate; // tokens/mspublic boolean tryAcquire(long needed) {long current = tokens.get();if (current >= needed) {return tokens.compareAndSet(current, current - needed);}return false;}// 定时任务补充令牌public void refill() {long current = tokens.get();long newTokens = Math.min(capacity, current + refillRate);tokens.set(newTokens);}}
2.2.2 核销服务
- 分布式锁:使用Redis实现优惠券核销互斥(Redis+Lua示例):
```lua
— 核销优惠券
local key = KEYS[1]
local userId = ARGV[1]
local couponId = ARGV[2]
if redis.call(“HGET”, key, “status”) == “UNUSED” then
redis.call(“HSET”, key, “status”, “USED”)
redis.call(“HSET”, key, “usedTime”, ARGV[3])
redis.call(“HSET”, key, “orderId”, ARGV[4])
return 1
else
return 0
end
### 2.2.3 数据同步- **双写缓冲**:使用Canal监听MySQL binlog,同步到ES/HBase- **最终一致性**:通过TCC事务模式保证数据准确# 三、技术选型与优化## 3.1 基础设施| 组件 | 选型方案 | 优化点 ||------------|------------------------------|----------------------------|| 负载均衡 | Nginx+Lua | 动态权重调整 || API网关 | Spring Cloud Gateway | 请求限流、熔断 || 缓存 | Redis Cluster(6节点) | 热点key分散、多级缓存 || 数据库 | MySQL分库分表(32库64表) | 读写分离、冷热数据分离 || 消息队列 | RocketMQ(双主双从) | 顺序消费、批量提交 |## 3.2 性能优化方案### 3.2.1 缓存策略- **多级缓存**:本地缓存(Caffeine)+分布式缓存(Redis)- **缓存预热**:大促前30分钟加载热点数据- **异步刷新**:使用消息队列通知缓存更新### 3.2.2 数据库优化- **索引优化**:```sql-- 优惠券表索引设计CREATE INDEX idx_user_status ON coupon(user_id, status);CREATE INDEX idx_expire_time ON coupon(expire_time);
- SQL优化:避免全表扫描,使用覆盖索引
- 分库分表:按user_id哈希分库,按create_time范围分表
3.3 并发控制
- 令牌桶限流:网关层限制每秒请求量
- 队列削峰:使用RocketMQ缓冲突发流量
- 异步处理:非实时操作(如数据统计)走异步队列
四、高可用设计
4.1 容灾方案
- 多活部署:同城双活+异地容灾
- 服务降级:非核心功能(如数据统计)降级
- 熔断机制:Hystrix实现服务熔断
4.2 监控体系
- 实时监控:Prometheus+Grafana监控QPS、延迟、错误率
- 日志分析:ELK收集分析请求日志
- 告警系统:基于阈值的自动告警(如P99>500ms)
五、安全防护
5.1 防刷策略
- IP限流:单IP每分钟最多100次请求
- 设备指纹:通过Canvas指纹识别机器请求
- 行为分析:基于用户行为模型识别异常
5.2 数据安全
- 传输加密:HTTPS+TLS1.3
- 存储加密:敏感字段(如优惠券码)AES加密
- 审计日志:完整记录操作轨迹
六、压测与调优
6.1 压测方案
- 工具选择:JMeter+InfluxDB+Grafana
- 压测场景:
- 阶梯增压测试(1k→100k QPS)
- 混合场景测试(发放:核销=3:7)
- 异常场景测试(网络中断、服务宕机)
6.2 调优案例
问题现象:核销服务P99延迟达800ms
根因分析:
- Redis集群单节点负载过高(QPS>5万)
- 核销逻辑中包含不必要的日志写入
优化措施:
- Redis集群扩容至12节点
- 异步化日志写入
- 优化Lua脚本(减少网络往返)
优化效果:P99延迟降至280ms
七、部署与运维
7.1 CI/CD流程
graph TDA[代码提交] --> B[单元测试]B --> C[代码扫描]C --> D[构建镜像]D --> E[灰度发布]E --> F[全量发布]
7.2 扩容策略
- 垂直扩容:数据库服务器升级(32核→64核)
- 水平扩容:服务节点自动伸缩(基于K8s HPA)
- 缓存扩容:Redis集群动态添加节点
八、成本优化
8.1 资源复用
- 混合部署:将非核心服务部署在相同节点
- 弹性计算:使用Spot实例处理异步任务
- 存储分级:冷数据迁移至对象存储
8.2 效率提升
- 无服务器化:将数据统计转为Lambda函数
- 自动化运维:通过Ansible实现批量管理
- 智能调优:基于AI的参数自动优化
九、实战经验总结
- 架构设计原则:先保证核心功能可用,再逐步优化
- 性能优化顺序:算法优化>缓存优化>架构优化>硬件升级
- 监控关键指标:QPS、错误率、P99延迟、系统负载
- 故障处理流程:定位问题→隔离影响→恢复服务→根因分析
通过以上方案,我们成功构建了支持10万级QPS的优惠券系统,在618大促期间稳定承载了每秒12.3万次请求,核销成功率99.997%,系统可用性达99.98%。实际部署中需根据业务特点调整参数,建议通过压测验证每个优化点的效果。