Redis 数据结构选型
Redis 提供了多种数据结构,每种结构都有其适用场景。合理选型能极大提升性能、节省内存、简化逻辑。
String(字符串)
基本特性:
- 最基础的数据类型,可存文本或二进制数据(如图片、序列化对象)
- 支持设置过期时间(TTL)
- 支持原子操作:INCR、DECR、INCRBY、SETNX 等
典型应用场景:
- 缓存 HTML 片段、JSON 数据、序列化对象
- 计数器(如文章阅读数、用户登录次数)→
INCR key - 分布式锁 →
SET key value NX PX timeout - 验证码、Session Token → 设置 TTL 自动过期
注意事项:
- 单个 value 最大 512MB,但建议控制在 10KB 以内,避免阻塞
- 避免大 Key(如存几万条数据的 JSON),影响 Redis 性能和网络传输
Hash(哈希表)
基本特性:
- 类似 Map,一个 Key 包含多个 field-value 对
- 支持对单个 field 操作(HSET, HGET, HINCRBY)
- 内存效率高,适合存储对象
典型应用场景:
- 存储对象:如用户信息
{id: 1, name: "Alice", age: 25}1 2HSET user:1001 name "Alice" age 25 city "Beijing" HGET user:1001 name - 商品属性、配置项、页面模块缓存
- 替代多个 String Key,减少 Key 数量,便于管理
注意事项:
- Redis 3.2+ 对小 Hash 有内存优化(ziplist 编码),字段少时更省空间
- 避免一个 Hash 存几万个 field(如用户所有行为日志),会退化成 hashtable,内存膨胀 + 操作慢
List(列表)
基本特性:
- 双向链表,支持从两端插入/弹出(LPUSH/RPUSH, LPOP/RPOP)
- 支持按索引访问(LINDEX)、范围获取(LRANGE)
- 可用作队列或栈
典型应用场景:
- 消息队列(简单场景)→ LPUSH + BRPOP(阻塞消费)
- 最新 N 条数据:如朋友圈最新动态、用户操作日志
- 任务队列(配合 Worker 消费)
注意事项:
- 不支持按内容删除,删除中间元素效率低(O(N))
- 避免超长 List(> 1 万),会阻塞 Redis
- 生产环境建议用专业 MQ(如 Kafka/RabbitMQ),List 仅用于轻量级场景
Sorted Set(有序集合,ZSet)
基本特性:
- 每个成员带一个分数(score),按分数排序
- 支持范围查询(ZRANGEBYSCORE)、排名(ZRANK)、分页
- 成员唯一,分数可重复
典型应用场景:
- 排行榜:游戏积分榜、热销商品榜、用户财富榜
1 2ZADD board 95 "userA" 87 "userB" 99 "userC" ZREVRANGE board 0 9 WITHSCORES ## 获取Top10 - 延时任务队列:score = 执行时间戳,定时轮询 ZRANGEBYSCORE
- 去重 + 排序:如带权重的推荐列表
注意事项:
- 内部使用跳跃表(SkipList)实现,插入/查询 O(logN)
- 避免频繁更新大量成员分数(如每秒更新百万用户积分),性能下降
- 使用 ZREMRANGEBYRANK / ZREMRANGEBYSCORE 定期清理过期数据
数据结构选型对比表
| 需求场景 | 推荐结构 | 理由说明 |
|---|---|---|
| 存单个值/对象 | String | 简单直接,支持原子操作 |
| 存对象多个字段 | Hash | 节省内存,支持字段级操作 |
| 存列表/队列/最新 N 条 | List | 双端操作,天然队列 |
| 排序/排行榜/范围查询 | Sorted Set | 自动排序,支持范围和排名 |
| 去重集合 | Set | 成员唯一,支持交并差运算 |
选型口诀:
“单值用 String,对象用 Hash,队列用 List,排序用 ZSet,去重用 Set”
Redis 持久化机制
Redis 是内存数据库,为防止宕机数据丢失,提供两种持久化机制:
RDB(Redis DataBase)快照
原理:
- 在指定时间间隔内,将内存数据全量写入二进制文件(dump.rdb)
- 可配置:save 900 1 → 900 秒内至少 1 次修改则触发
优点:
- 文件紧凑,恢复速度快
- 适合备份、灾难恢复
- 对性能影响小(fork 子进程处理)
缺点:
- 可能丢失最后一次快照后的数据(最多几分钟)
- 数据量大时 fork 耗时,可能阻塞主线程
适用场景:
- 允许少量数据丢失的场景(如缓存)
- 每日备份、主从同步的基准数据
AOF(Append Only File)日志
原理:
- 记录每个写操作命令(如 SET、HSET),以文本形式追加到 aof 文件
- 支持三种同步策略:
appendfsync always:每条命令都刷盘 → 最安全,性能差appendfsync everysec(默认)→ 每秒刷盘,平衡安全与性能appendfsync no→ 由操作系统决定 → 性能最好,风险最大
优点:
- 数据安全性高,最多丢失 1 秒数据
- 日志可读,支持人工修复
缺点:
- 文件体积大(相比 RDB)
- 恢复速度慢(需重放所有命令)
- 需要定期
BGREWRITEAOF重写压缩文件
适用场景:
- 对数据一致性要求高的场景(如订单状态、账户余额)
混合持久化(Redis 4.0+)
- RDB + AOF 结合:AOF 重写时,先写 RDB 格式数据,再追加增量 AOF 命令
- 兼顾恢复速度和数据安全
- 推荐生产环境开启
持久化常见问题:
- fork 阻塞:内存越大,fork 越慢 → 建议单实例内存 ≤ 10GB
- AOF 膨胀:忘记配置 auto-aof-rewrite → 手动执行
BGREWRITEAOF - 磁盘 IO 瓶颈:建议 AOF/RDB 文件写入高速 SSD,与数据盘分离
- 主从同步优先用 RDB:从节点首次同步使用 RDB 文件,效率高
Redis 集群方案
单机 Redis 有容量和性能瓶颈,生产环境必须集群化。主流方案:
Redis Cluster(官方集群,推荐)
原理:
- 数据分片(Sharding):16384 个槽(slot),每个 Key 通过 CRC16 算法定位到槽
- 多个主节点各自负责一部分槽,从节点负责故障转移
- 客户端直连任意节点,自动重定向(MOVED/ASK)
优点:
- 官方支持,无中心架构,扩展性好
- 自动故障转移(基于 Gossip 协议)
- 支持在线扩容/缩容
缺点:
- 不支持多 Key 跨槽操作(如 SUNION、MGET 跨节点 Key 会报错)
- 运维复杂度高(需管理多个节点、slots 分配)
- 客户端需支持 Cluster 协议(如 redis-py-cluster)
部署建议:
- 至少 6 个节点(3 主 3 从)保证高可用
- 避免“热点 Key”集中在某个节点 → 合理设计 Key 前缀打散
- 使用
redis-cli --cluster工具管理集群
哨兵模式(Sentinel)
原理:
- 主从复制 + 哨兵监控:Sentinel 监控主节点状态,自动故障转移
- 数据不分片,所有节点数据一致(读写分离)
优点:
- 架构简单,适合读多写少场景
- 自动主从切换,高可用
- 兼容老版本客户端
缺点:
- 写操作仍单点(主节点),容量受单机限制
- 不能水平扩展写能力
适用场景:
- 数据量不大(< 20GB),但要求高可用的缓存场景
- 作为 Redis Cluster 的补充(如配置中心、Session 存储)
代理分片(如 Codis / Twemproxy)
原理:
- 引入代理层(Proxy),客户端连接 Proxy,Proxy 路由到后端 Redis 实例
- 数据分片规则由 Proxy 管理(一致性哈希、取模等)
优点:
- 客户端无需改造,兼容任意 Redis 客户端
- 支持平滑扩容、数据迁移
缺点:
- 引入额外组件(Proxy),增加延迟和运维成本
- Proxy 成为单点或需做 HA(如 LVS + Keepalived)
现状:
- Codis 由豌豆荚开源,目前维护较少
- Twemproxy(Twitter 开源)功能较简单,不支持自动故障转移
- 新项目建议直接用 Redis Cluster
集群方案对比
| 方案 | 数据分片 | 故障转移 | 扩展性 | 客户端兼容 | 适用场景 |
|---|---|---|---|---|---|
| Redis Cluster | ✅ | ✅ | ✅ | 需支持协议 | 大数据量、高并发读写 |
| Sentinel | ❌ | ✅ | ❌ | ✅ | 中小规模、高可用缓存 |
| 代理分片 | ✅ | 部分支持 | ✅ | ✅ | 老系统平滑迁移 |
集群常见问题:
- 跨槽操作失败:避免在 Cluster 中使用 multi-key 命令(如 KEYS *、MGET 跨节点)
- 热点 Key:导致某节点 CPU/带宽打满 → 使用本地缓存 + Key 打散(加随机前缀)
- 大 Key 迁移卡顿:集群扩容时,大 Key 迁移会阻塞 → 提前拆分或禁用迁移
- 客户端连接管理:建议使用连接池,避免频繁创建连接