2. Redis 基础回顾:核心数据结构与运行机制

在深入削峰与缓存一致性实战之前,必须牢固掌握 Redis 的五大基础数据结构、单线程事件驱动模型以及持久化机制。这些是理解 Redis 高性能、原子性操作以及数据安全特性的基石。

2.1 五大基础数据结构

Redis 是一个键值对数据库,但它的值并不仅仅是简单的字符串。它支持多种数据结构,每种结构都针对特定场景进行了优化。下表总结了五种最常用的数据结构及其核心特性:

数据结构 内部编码 核心命令示例 时间复杂度 典型应用场景
String int, embstr, raw SET, GET, INCR, DECR, MSET O(1) 计数器、分布式锁、Session 共享、缓存对象
Hash ziplist, hashtable HSET, HGET, HGETALL, HINCRBY O(1) 平均 存储对象(如用户信息、商品详情)、购物车
List quicklist LPUSH, RPUSH, LPOP, BRPOP, LRANGE O(1) 头尾操作 消息队列、时间线(Timeline)、最新列表
Set intset, hashtable SADD, SREM, SMEMBERS, SINTER, SUNION O(1) 增删查 标签系统、共同好友、抽奖、去重
ZSet ziplist, skiplist ZADD, ZRANGE, ZREVRANGE, ZRANK, ZINCRBY O(log N) 排行榜、延时队列、优先级队列、限流滑动窗口
实战提示: 在削峰场景中,List 常用于构建异步队列(LPUSH + BRPOP),ZSet 则用于实现基于时间戳的滑动窗口限流或延时任务调度。选择合适的数据结构能显著降低系统复杂度。

2.2 Redis 单线程模型

Redis 的核心处理逻辑是单线程的,这意味着它使用一个主线程(Main Reactor)来处理所有客户端的命令请求。这个模型是 Redis 高性能的关键之一。

  • 核心机制: 基于 I/O 多路复用(如 epoll/kqueue)和事件循环(Event Loop)。主线程在一个循环中同时监听多个 Socket 上的可读/可写事件。
  • 处理流程: 当有新的连接请求或命令请求到达时,事件处理器将其放入队列,然后单线程依次从队列中取出事件并执行对应的回调函数。
  • 优势:
    • 无锁竞争: 避免了多线程编程中常见的锁竞争、上下文切换和死锁问题,数据访问天然线程安全。
    • 可预测性: 执行顺序确定,性能模型简单,易于理解和优化。
    • 高性能: 纯内存操作 + 非阻塞 I/O + 单线程避免了多线程开销,使得 Redis 在绝大多数场景下都能达到极高的吞吐量(通常可达 10万+ QPS)。
  • 注意事项: 单线程意味着所有命令都是串行执行的。如果某个命令执行时间过长(如 KEYS *、SMEMBERS 大集合、HGETALL 大哈希),会阻塞后续所有命令,导致 Redis 响应延迟飙升。这是生产环境必须避免的“慢查询”问题。
避坑指南: 严禁在生产环境使用 KEYS * 命令。应使用 SCAN 系列命令进行渐进式遍历。对于大 Key(Big Key),应通过拆分、异步删除(UNLINK)等方式处理,避免阻塞主线程。
Redis 单线程事件循环模型 Redis 单线程事件循环模型 Client 1 Client 2 Client N I/O 多路复用 (epoll/kqueue) 事件队列 (Event Queue) 单线程处理器 (Main Reactor) 命令执行 (串行) 内存 数据

2.3 Redis 持久化机制

Redis 是内存数据库,但为了防止数据丢失,它提供了两种主要的持久化方式:RDB(快照)和 AOF(追加文件)。理解它们的原理和差异,对于设计高可用缓存架构至关重要。

2.3.1 RDB(Redis Database)

  • 原理: 在指定的时间间隔内,将内存中的数据集快照(Snapshot)写入磁盘的二进制文件(默认 dump.rdb)。
  • 触发方式:
    • 手动: SAVE(同步阻塞)、BGSAVE(异步,fork 子进程执行)。
    • 自动: 根据配置文件中的 save 指令(如 save 900 1 表示 900 秒内至少 1 个 key 变化则触发)。
  • 优点: 文件紧凑,适合备份和灾难恢复;恢复速度比 AOF 快。
  • 缺点: 可能会丢失最后一次快照之后的所有数据;fork 子进程时,如果数据集很大,可能会导致服务短暂停顿。

2.3.2 AOF(Append Only File)

  • 原理: 以日志的形式记录每个写操作(命令),Redis 重启时会重新执行这些命令来恢复数据。
  • 刷盘策略(appendfsync):
    • always: 每次写命令都同步到磁盘,最安全,但性能最慢。
    • everysec: 每秒同步一次,兼顾性能与安全(推荐,最多丢失 1 秒数据)。
    • no: 由操作系统决定何时同步,性能最快,但数据安全性最差。
  • 优点: 数据安全性高(最多丢失 1 秒数据);AOF 文件可读,便于误操作修复。
  • 缺点: 相同数据集下,AOF 文件体积通常比 RDB 大;恢复速度比 RDB 慢。
RDB 与 AOF 持久化流程对比 RDB 与 AOF 持久化流程对比 RDB 快照 1. 触发 BGSAVE 2. Fork 子进程 3. 子进程写临时 RDB 4. 替换旧 RDB 文件 AOF 日志 1. 执行写命令 2. 追加到 AOF 缓冲区 3. 根据策略刷盘 (always/everysec/no) 4. 写入 AOF 文件 对比:RDB 是数据快照,恢复快但可能丢数据;AOF 是命令日志,数据更安全但恢复慢、文件大。
生产建议: 通常建议同时开启 RDB 和 AOF。RDB 用于快速恢复和备份,AOF(everysec)用于保证数据安全。在 Redis 重启时,会优先使用 AOF 文件来恢复数据,因为它通常更完整。