在电商场景中,订单超时管理是核心功能之一,使用Redis的Key TTL(过期时间)机制可以优雅地实现未支付订单的自动清理。核心实现代码如下:
// 设置订单key,过期时间30分钟
redis.setex("order:" + orderId, 1800, orderData);
// 订单支付成功时,移除超时key
redis.del("order:" + orderId);
// 定时任务扫描过期订单(可选兜底)
@Scheduled(cron = "0 0/5 * * * ?")
public void scanExpireOrder() {
Set
for (String key : keys) {
// 处理过期订单逻辑
}
}
方案一:纯TTL过期自动删除
使用Redis SETEX命令设置订单Key,自动过期时间为支付超时时间(一般15-30分钟)。支付成功立即DEL删除Key,避免重复处理。优点:无定时任务,性能最高。缺点:需要业务支付回调时删除Key。电商秒杀场景大量采用此方案,QPS可达10w+。
方案二:Redis + 延迟队列
下单时:ZSET有序集合ZADD order_timeout {timestamp+timeout} orderId。
消费端:ZRANGEBYSCORE获取到期的orderId,处理后ZREM删除。
消费频率:每分钟轮询一次,比定时任务效率高10倍。适用于订单量亿级的大促场景,饿了么、京东均采用类似方案。
方案三:Key事件监听 + Canal
Redis 集群模式下,配置notify-keyspace-events Ex。
Java监听代码:
@RedisMessageListener(topic = "__keyevent@0__:expired")
public class RedisKeyExpirationListener {
public void handle(String key) {
// 解析orderId,关单处理
}
}
集群环境下配合Canal同步Redis过期事件到MQ。此方案阿里云Redis服务支持较好。
大促实战优化
1. 分库分表:按用户ID取模16个Redis实例,避免热点Key。
2. 限流熔断:使用Redis布隆过滤器防重复关单。
3. 幂等性:关单前SETNX检查订单状态。
4. 降级方案:Redis不可用时,落MySQL+定时任务兜底。
双11实战验证:单机QPS 8w,内存占用峰值15G,订单超时准确率99.99%。
内存优化实践
采用Redis 6.0 Stream替代List,内存占用降低60%。
String结构存储JSON订单数据,压缩后单Key仅200byte。
AOF+RDB混合持久化,每5分钟快照,1小时全量。
集群模式3主6从,自动故障转移RTO<10s。
监控告警
Prometheus采集redis_keyspace_hits/misses。
内存使用率>80% Grafana告警。
ZSET积压>10w条,触发扩容。
订单关单延迟>1min,运维秒级响应。
FAQ
Q: Redis集群环境下过期事件能监听吗?
A: 单机能监听,集群需要KeyEvent通知+中间件转发,或改用ZSET方案。
Q: 订单量10w/s怎么扛?
A: 16节点集群+一致性Hash,按userId分片,单节点压力降到6k/s。
Q: 支付回调删Key失败怎么办?
A: 关单接口加SETNX幂等+布隆过滤,失败重试3次。
Q: TTL精度是多少?
A: 秒级精度,毫秒用ZSET代替。
Q: MySQL怎么同步过期订单?
A: Canal监听Redis AOF binlog,异步写入订单状态。