2. Redis 基础回顾:核心数据结构与持久化机制

在构建搜索缓存闭环之前,必须牢固掌握 Redis 的两大基石:五种核心数据结构 与 两种持久化机制。数据结构决定了缓存能“存什么、怎么查”,持久化决定了缓存“断电后能否恢复”。本章从实战角度梳理这些基础,为后续的搜索缓存设计打下坚实的地基。

2.1 五种核心数据结构

Redis 不是简单的键值存储,它的值类型决定了操作能力。下表总结了五种数据结构的核心特征与典型应用场景:

数据结构 内部编码 核心命令 时间复杂度 典型场景
String int / embstr / raw GET, SET, INCR, DECR O(1) 计数器、分布式锁、Session 缓存
Hash ziplist / hashtable HGET, HSET, HGETALL O(1) 单字段 对象缓存(用户信息、商品详情)
List quicklist LPUSH, RPUSH, LPOP, LRANGE O(1) 头尾 / O(N) 范围 消息队列、时间线、最新动态
Set intset / hashtable SADD, SREM, SISMEMBER, SUNION O(1) 单元素 / O(N) 集合运算 标签系统、去重、共同关注
Sorted Set ziplist / skiplist ZADD, ZRANGE, ZRANK, ZREVRANK O(log N) 增删查 排行榜、延迟队列、范围查询
实战提示: 在搜索缓存场景中,Hash 用于缓存文档字段(如标题、摘要、评分),Sorted Set 用于存储搜索结果的排序索引(以分数表示相关性),Set 用于标签过滤与交集运算。

2.1.1 String:最基础的缓存单元

String 是 Redis 最基础的值类型,最大支持 512MB。除了简单的键值缓存,INCR 命令常用于实现搜索请求计数器、限流令牌桶。在搜索缓存中,String 适合存储序列化后的单条搜索结果或聚合统计值。

# 缓存搜索结果摘要(JSON 序列化)
SET search:cache:query:redis "{\"total\": 120, \"docs\": [...]}" EX 300

# 搜索请求计数器
INCR search:stats:requests:2025-04-01

2.1.2 Hash:结构化对象缓存

Hash 允许对对象的单个字段进行读写,避免序列化整个对象。在搜索缓存中,Hash 非常适合存储文档的元数据字段,支持部分更新而不影响其他字段。

# 缓存文档元数据
HSET doc:1001 title "Redis 实战" author "张三" score 9.5
HSET doc:1002 title "缓存设计" author "李四" score 8.7

# 只获取标题字段
HGET doc:1001 title

2.1.3 List:消息队列与分页

List 基于双向链表实现,头尾操作时间复杂度 O(1)。在搜索系统中,List 可用于构建异步索引写入队列,或缓存搜索结果的分页列表。

# 索引写入队列
LPUSH index:queue "{\"doc_id\": 1001, \"action\": \"update\"}"

# 缓存搜索结果分页(每页 20 条)
RPUSH search:result:page:1 "doc:1001" "doc:1002" ...

2.1.4 Set:标签与过滤

Set 提供高效的成员判断与集合运算。在搜索缓存中,Set 用于存储文档的标签集合,通过 SINTER 实现多标签过滤,通过 SDIFF 实现排除逻辑。

# 为文档打标签
SADD tag:redis doc:1001 doc:1002 doc:1003
SADD tag:cache doc:1001 doc:1004

# 同时包含 redis 和 cache 标签的文档
SINTER tag:redis tag:cache

2.1.5 Sorted Set:排序与范围查询

Sorted Set 是搜索缓存的核心数据结构。每个元素关联一个 double 类型的分数,Redis 通过跳跃表实现高效的按分数范围查询与排名计算。在搜索系统中,分数可以映射为相关性评分、发布时间戳或价格。

# 存储搜索结果排序索引
ZADD search:index:keyword:redis 9.5 doc:1001
ZADD search:index:keyword:redis 8.7 doc:1002
ZADD search:index:keyword:redis 7.2 doc:1003

# 获取 Top 10 结果
ZREVRANGE search:index:keyword:redis 0 9 WITHSCORES

# 按分数范围过滤(相关性 > 8.0)
ZRANGEBYSCORE search:index:keyword:redis 8.0 +inf
架构要点: Sorted Set 的 ZREVRANGE 与 ZRANGEBYSCORE 是搜索缓存闭环中“排序”与“过滤”两个核心操作的底层实现基础。合理设计分数映射规则,可以避免在应用层进行二次排序。
五种数据结构在搜索缓存中的角色映射 搜索缓存闭环 String Hash List Set Sorted Set 角色说明: • String → 缓存序列化搜索结果、计数器、分布式锁 • Hash → 缓存文档字段(标题、摘要、评分),支持部分更新 • List → 索引写入队列、搜索结果分页缓存 • Set → 标签存储、多标签交集/差集过滤 • Sorted Set → 搜索排序索引(分数=相关性/时间戳)、范围查询、Top N

2.2 Redis 持久化:RDB 与 AOF

持久化是 Redis 从“缓存”走向“数据库”的关键能力。在搜索缓存闭环中,持久化决定了索引数据在重启后能否快速恢复,以及数据丢失的容忍度。Redis 提供两种持久化机制:RDB(快照) 与 AOF(追加文件)。

2.2.1 RDB(Redis Database Backup)

RDB 通过创建内存数据的二进制快照实现持久化。它适合大规模数据的定期备份,恢复速度极快,但可能丢失最后一次快照之后的数据。

特性 说明
触发方式 手动 SAVE(同步阻塞)/ BGSAVE(异步 fork);自动根据配置 save <seconds> <changes>
文件格式 二进制压缩文件 dump.rdb,体积小
恢复速度 极快,直接加载到内存
数据丢失 可能丢失最后一次快照后的所有写入
适用场景 冷备份、灾难恢复、搜索索引的定期全量快照
# 手动触发异步快照
BGSAVE

# 自动触发配置(60 秒内至少 10000 次写入则生成快照)
save 60 10000

# 查看最后一次成功快照的时间
LASTSAVE

2.2.2 AOF(Append Only File)

AOF 通过记录每次写操作的命令日志实现持久化。它提供更高的数据安全性(可配置 fsync 策略),但文件体积较大,恢复速度相对较慢。

特性 说明
记录方式 追加写操作命令,文本协议格式
fsync 策略 always(每次写入同步,最安全)、everysec(每秒同步,推荐)、no(由 OS 决定)
文件重写 BGREWRITEAOF 压缩重复命令,减少文件体积
恢复速度 较慢,需逐条回放命令
适用场景 需要高数据安全性的搜索索引增量更新
# 开启 AOF(redis.conf)
appendonly yes
appendfsync everysec

# 手动触发 AOF 重写
BGREWRITEAOF
避坑指南: 在搜索缓存场景中,如果使用 AOF 且 fsync 设置为 always,每次搜索结果的写入都会触发磁盘同步,会显著降低写入吞吐量。建议使用 everysec 策略,在安全性与性能之间取得平衡。对于搜索索引的全量快照,RDB 是更高效的选择。

2.2.3 混合持久化(Redis 4.0+)

Redis 4.0 引入了混合持久化模式,将 RDB 快照与 AOF 增量日志结合。在 AOF 重写时,将当前内存数据以 RDB 格式写入 AOF 文件头部,后续增量命令以 AOF 格式追加。这种模式兼顾了 RDB 的快速恢复与 AOF 的低数据丢失。

# 开启混合持久化(redis.conf)
aof-use-rdb-preamble yes
RDB 与 AOF 持久化流程对比 RDB 快照流程 触发 BGSAVE fork 子进程 子进程写临时 RDB 原子替换 dump.rdb AOF 追加流程 写命令到达 追加到 AOF 缓冲区 fsync 刷盘 写入 AOF 文件 对比总结: • 数据安全性:AOF(everysec)> RDB(可能丢失最后一次快照) • 恢复速度:RDB(直接加载)> AOF(逐条回放) • 文件体积:RDB(二进制压缩)< AOF(文本协议,可重写压缩) • 对性能影响:RDB(fork 子进程,COW 机制)< AOF(always 模式频繁 fsync) • 搜索缓存推荐:全量快照用 RDB + 增量日志用 AOF everysec + 混合持久化 • 恢复优先级:AOF 文件优先级高于 RDB,Redis 启动时优先加载 AOF

2.3 持久化策略选择建议

在搜索缓存闭环中,持久化策略的选择取决于对数据丢失容忍度与恢复速度的要求。以下为三种典型场景的推荐配置:

  • 场景一:纯缓存,可重建 —— 关闭持久化(save "",appendonly no),仅作为加速层,数据丢失后从数据库重建。
  • 场景二:搜索索引缓存,允许少量丢失 —— RDB 每 5 分钟快照 + AOF everysec,兼顾恢复速度与数据安全。
  • 场景三:搜索索引主存储,零容忍丢失 —— AOF always + 定期 RDB 快照 + 混合持久化,配合 Redis Sentinel 或 Cluster 实现高可用。
架构决策: 在搜索缓存闭环中,建议将持久化策略与缓存失效策略联动。例如,RDB 快照触发时,同时标记缓存版本号,恢复后自动触发增量索引重建,确保数据一致性。