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-500ms5-20ms10-50x
插入时间10-50ms1-5ms5-10x
删除时间20-100ms1-5ms10-100x
并发能力~100 QPS~10000 QPS100x
精度秒级毫秒级-
内存占用低(磁盘)高(内存)-

性能测试


想一想

思考 1

如何处理 Redis 宕机时的数据丢失问题?

参考答案

问题分析:

Redis 是内存数据库,宕机可能导致数据丢失。

解决方案:

1. 开启 AOF 持久化

验证要点

  • 命令只用于验证系统状态,读者不需要记具体参数。

优点: 数据丢失最多 1 秒 缺点: 性能略有下降


2. 双层存储(Redis + 数据库)


3. 使用 Redis 哨兵或集群

验证要点

  • 命令只用于验证系统状态,读者不需要记具体参数。

优点: 自动故障转移 缺点: 需要至少 3 个节点


4. 定期备份

最佳实践建议:

  1. 必须开启 AOF:保证数据持久化
  2. 双层存储:Redis + 数据库,性能和可靠性兼顾
  3. 使用哨兵/集群:保证高可用
  4. 定期备份:防止数据损坏