这是 Beta 探索课程,内容结构、实验步骤和示例可能会继续调整。
Redis ZSet 基础
从数据库到 Redis
当我们的订单量突破 10 万/天后,数据库轮询方案开始吃力:
性能瓶颈:
- 数据库查询:每次 100-500ms
- 网络延迟:每次 10-50ms
- 并发限制:数据库连接池有限
- 总吞吐量:~100 任务/秒
目标:
- 查询时间:< 10ms
- 总吞吐量:> 1000 任务/秒经过调研,我们决定尝试 **Redis ZSet(有序集合)**方案。
什么是 ZSet?
Redis ZSet 是 Redis 的 5 种基础数据结构之一,全称为 Sorted Set(有序集合)。
ZSet 的特点
| 特性 | 说明 |
|---|---|
| 有序 | 元素按照 score 排序 |
| 唯一 | member 不重复 |
| 快速 | O(log n) 的插入、删除、查询 |
| 范围查询 | 支持按 score 范围查询 |
ZSet 的数据结构
ZSet 内部使用跳表(Skip List)实现:
跳表结构:
Level 3: 1 ─────────────────────────────► 5 ──────────────────► 9
│ │
Level 2: 1 ──────────► 3 ───────────────► 5 ──────────► 7 ───► 9
│ │ │ │
Level 1: 1 ──► 2 ──► 3 ──► 4 ──► 5 ──► 6 ──► 7 ──► 8 ──► 9
│ │ │ │ │ │ │ │ │
Level 0: 1 ──► 2 ──► 3 ──► 4 ──► 5 ──► 6 ──► 7 ──► 8 ──► 9时间复杂度:
- 插入:O(log n)
- 删除:O(log n)
- 查询范围:O(log n + m),m 为结果数量
ZSet 实现延时队列的原理
核心思想
延时队列 = ZSet + 时间戳
- member: 任务 ID
- score: 执行时间戳数据模型
基本实现
使用示例
ZSet 延时队列的优缺点
优点
| 优点 | 说明 |
|---|---|
| ✅ 高性能 | O(log n) 的时间复杂度,查询快 |
| ✅ 高精度 | 可以精确到毫秒 |
| ✅ 范围查询 | 支持按时间范围查询 |
| ✅ 易扩展 | 可以增加 Redis 节点 |
| ✅ 支持取消 | O(log n) 删除,效率高 |
缺点
| 缺点 | 说明 | 解决方案 |
|---|---|---|
| ❌ 内存占用 | 所有任务都在内存中 | 分层存储,长延时任务用数据库 |
| ❌ 持久化 | Redis 默认不持久化 | 开启 AOF 或 RDB |
| ❌ 单点故障 | Redis 挂了怎么办 | 使用 Redis 集群或哨兵 |
| ❌ 容量限制 | 受内存大小限制 | 任务分层或使用 Redis Cluster |
性能对比
数据库轮询 vs Redis ZSet
| 维度 | 数据库轮询 | Redis ZSet | 提升 |
|---|---|---|---|
| 查询时间 | 100-500ms | 5-20ms | 10-50x |
| 插入时间 | 10-50ms | 1-5ms | 5-10x |
| 删除时间 | 20-100ms | 1-5ms | 10-100x |
| 并发能力 | ~100 QPS | ~10000 QPS | 100x |
| 精度 | 秒级 | 毫秒级 | - |
| 内存占用 | 低(磁盘) | 高(内存) | - |
性能测试
想一想
思考 1
如何处理 Redis 宕机时的数据丢失问题?
参考答案
问题分析:
Redis 是内存数据库,宕机可能导致数据丢失。
解决方案:
1. 开启 AOF 持久化
验证要点
- 命令只用于验证系统状态,读者不需要记具体参数。
优点: 数据丢失最多 1 秒 缺点: 性能略有下降
2. 双层存储(Redis + 数据库)
3. 使用 Redis 哨兵或集群
验证要点
- 命令只用于验证系统状态,读者不需要记具体参数。
优点: 自动故障转移 缺点: 需要至少 3 个节点
4. 定期备份
最佳实践建议:
- ✅ 必须开启 AOF:保证数据持久化
- ✅ 双层存储:Redis + 数据库,性能和可靠性兼顾
- ✅ 使用哨兵/集群:保证高可用
- ✅ 定期备份:防止数据损坏