Redis Cluster

Redis Cluster:从 Sentinel 到分片与故障转移 Redis 高可用有两个常见答案:Sentinel 和 Cluster。它们并不是同一套方案的两个名字。 Sentinel 解决的是一组主从节点如何自动切主;Cluster 除了故障转移,还要把数据和请求分散到多个 master。理解 Cluster,只需要先抓住一条主线: TEXTkey -> hash slot -> master -> 执行命令 | +-> replica 复制并在故障后接管 下文先完成选型,再沿着一次请求看 slot 路由,最后解释迁移和故障转移。 1. Sentinel 和 Cluster 怎么选 Sentinel(哨兵模式)由两部分组成: TEXTRedis 数据节点:1 个 master + 若干 replica,彼此保存同一份完整数据 Sentinel 进程:监控 master,协商故障状态,选择并提升 replica Sentinel 进程不保存业务数据,也不负责分片。切主以后,客户端需要发现新 master 并重新连接。它提高了可用性,但单个复制组的容量和写入吞吐仍受一个 master 限制。 所谓“哨兵集群”,通常是用多个 Sentinel 共同监控主从复制组,常见部署是 3 个。达到配置的 quorum 后,master 才会被判为客观下线;真正发起故障转移还需要获得 Sentinel 多数授权。 Cluster 则把数据拆到多个 master: ...

July 14, 2026

Redis Persistence

Redis 持久化:从一条 SET 命令看 RDB 与 AOF 沿着下面这条命令观察数据怎样进入内存、AOF 和 RDB,最后又怎样在重启时恢复: REDISSET token abc EX 60 它表达了两项状态: TEXTvalue(token) = "abc" expire(token) = 当前时间 + 60 秒 Redis 有两种方式把这两项状态保存到磁盘: TEXTRDB:保存某个时刻的 value + expire 快照 AOF:保存能够重建 value + expire 的写命令 主要源码入口: 环节 源码 SET 执行与过期时间改写 src/t_string.c:setGenericCommand 写命令传播 src/server.c:call、propagateNow AOF 编码、写入与刷盘 src/aof.c:feedAppendOnlyFile、flushAppendOnlyFile RDB 编码、保存与加载 src/rdb.c:rdbSave*、rdbLoadRio* AOF rewrite 与加载 src/aof.c:rewriteAppendOnlyFileBackground、loadAppendOnlyFiles 自动持久化调度 src/server.c:serverCron 下文每个 C 代码块首行都标注 源码文件:函数;/* ... */ 表示省略了与当前链路无关的源码。 ...

July 12, 2026

Redis Expire and Eviction

Redis 过期和淘汰:从 SET token abc EX 60 开始 先固定一条命令: TEXTSET token abc EX 60 这条命令写入了一个 key,并给它挂上 TTL。之后 token 会遇到两条删除路径: 路径 触发点 对 token 的影响 expire 过期 到达 EX 60 对应的过期时间 读路径把它视为已过期,后台扫描也可能删除它 eviction 淘汰 Redis 内存超过 maxmemory 按 maxmemory-policy 判断它是否进入淘汰候选 全文围绕这条 token 主线展开:TTL 写到哪里、到期后怎样被发现、删除时发生什么、 内存压力下又怎样被淘汰策略处理。 文中的源码摘录保留主线分支,省略 Cluster、module、统计细节和错误处理。 SET token abc EX 60 写入了什么 Redis 的 DB 里有两套和 token 相关的索引: C/* server.h,省略其他字段 */ typedef struct redisDb { kvstore *keys; /* 当前 DB 的全部 key */ kvstore *expires; /* 设置了 TTL 的 key */ unsigned long expires_cursor; } redisDb; 执行 SET token abc EX 60 后,token 会出现在 db->keys 中;因为带 TTL, 它也会出现在 db->expires 中。两套索引指向同一个 kvobj,过期时间跟着 kvobj 走: ...

July 12, 2026

Redis Event Loop

Redis 事件循环 这篇不按 API 一个个介绍,而是跟着一个具体请求读源码。先固定场景: TEXT系统:Linux,使用 epoll 连接:普通 TCP,不考虑 TLS 线程:io-threads = 1 监听 socket:fd = 6 客户端 socket:fd = 8 客户端发送:SET name alice 要追的不是一堆互相独立的函数,而是下面两次唤醒: TEXT第一次 epoll_wait 返回 fd=6 可读 -> accept 新连接 -> 得到 fd=8 -> 给 fd=8 注册读回调 第二次 epoll_wait 返回 fd=8 可读 -> 读请求 -> 执行 SET -> 生成 +OK -> 下一轮 beforeSleep 写回客户端 主要源码按这个顺序看: ...

July 11, 2026

Redis Replication

Redis 复制 用这条命令看 Redis 复制的数据流: BASHSET token abc EX 60 它在 master 上执行一次,随后进入复制流。replica 重放的命令会被改写为: TEXTSET token abc PXAT <absolute-millisecond-timestamp> 主线: TEXTREPLICAOF -> connectWithMaster -> syncWithMaster -> PSYNC -> CONTINUE:补 backlog -> FULLRESYNC:加载 RDB 基线 SET token abc EX 60 -> 改写 PXAT -> 写入复制流 -> backlog + replica 输出缓冲 -> replica 以 CLIENT_MASTER 身份重放 以下代码均为源码截取,只保留影响这条路径的判断和赋值。 复制历史 部分重同步依赖 replid + offset + backlog。 ...

July 11, 2026

Redis Command Execution

Redis 命令执行 这篇看一条命令从客户端发到 Redis 后,源码里大概怎么走。例子还是: BASHSET name alice 客户端一般发的是 RESP: TEXT*3\r\n$3\r\nSET\r\n$4\r\nname\r\n$5\r\nalice\r\n 主线可以压成这一条: TEXTreadQueryFromClient -> processInputBuffer -> processMultibulkBuffer / processInlineBuffer -> preprocessCommand -> processCommandAndResetClient -> processCommand -> call -> setCommand -> addReply -> handleClientsWithPendingWrites / writeToClient 主要源码: 环节 源码 读请求、协议解析、回写 src/networking.c 查命令、校验、调度 src/server.c / src/server.h 命令声明 src/commands/*.json / src/commands.def SET 实现 src/t_string.c 写入数据库 src/db.c client:一条连接的执行现场 先看 server.h 里的 client,删掉大量无关字段后是这样: ...

July 11, 2026

Redis Datastructure

Redis 数据结构 本文按 Redis 8.x/unstable 源码写,重点看内存编码和自动转换。老版本里 ziplist、linkedlist 等编码已经不适合作为当前主线。 逻辑类型 (Type) 底层数据结构 (Internal Encoding) String int, embstr, raw (SDS) List listpack, quicklist Hash listpack, listpackEx, hashtable Set intset, listpack, hashtable ZSet listpack, skiplist + hashtable Stream rax + listpack graph TD A[redisObject] --> B{type} B -->|STRING| C[int / embstr / raw] B -->|LIST| D{size?} B -->|HASH| E{size?} B -->|SET| F{all int?} B -->|ZSET| G{size?} B -->|STREAM| S[rax + listpack] D -->|小| DL[listpack] D -->|大| DQ[quicklist] E -->|小| H[listpack] E -->|field TTL| HX[listpackEx / hashtable metadata] E -->|大| I[hashtable] F -->|yes & 少| J[intset] F -->|no & 小| K[listpack] F -->|大| FH[hashtable] G -->|小| L[listpack] G -->|大| M[skiplist + hashtable]每种类型根据数据量自动切换编码:小数据用紧凑结构省内存,大数据切高效结构保性能。 ...

February 12, 2026