Note

内存键值数据库


架构

Tip

命令单线程 + IO多路复用

  • 单线程处理命令:避免多线程锁竞争、上下文切换开销,保证命令的原子性

  • I/O 多路复用:用 epoll(Linux)/ kqueue 等同时监听大量连接,单线程也能支撑高并发

  • 6.0 之后引入多线程 I/O:只把网络读写(socket read/write)并行化,命令执行仍是单线程

客户端 → 多路复用器(epoll) → 事件分发 → 单线程命令处理 → 内存数据结构

数据结构

类型底层实现特点
StringSDS(简单动态字符串)记录长度、预分配、二进制安全
Listquicklist(ziplist + 双向链表)兼顾内存与性能
Hashziplist / hashtable小数据用 ziplist 省内存
Setintset / hashtable整数集合用 intset
ZSetziplist / skiplist + hashtable跳表实现范围查询 O(logN)

关键设计

  • SDS:O(1) 获取长度,避免缓冲区溢出,支持二进制数据

  • 跳表(skiplist):多层索引,实现有序集合的高效范围查询

  • 渐进式 rehash:字典扩容时分散到多次操作,避免单次阻塞


内存管理

过期删除策略(两种结合)

  1. 惰性删除:访问 key 时才检查是否过期
  2. 定期删除:每隔一段时间随机抽查部分 key 删除

内存淘汰策略(8 种)

  • noeviction:不淘汰,写入报错
  • allkeys-lru:所有 key 中淘汰最近最少使用的
  • volatile-lru:设置了过期时间的 key 中淘汰 LRU
  • allkeys-lfu / volatile-lfu:淘汰最不经常使用的

持久化

RDB(快照)

  • 某一时刻把内存数据全量写入二进制文件
  • bgsave 通过 fork 子进程完成,利用 写时复制(COW)
  • 优点:文件小、恢复快;缺点:可能丢数据

AOF(追加日志)

  • 记录每条写命令,重启时重放
  • 刷盘策略:always / everysec / no
  • AOF 重写:压缩日志体积(也是 fork 子进程)
  • 4.0 后支持 混合持久化:RDB 全量 + AOF 增量

高可用与集群

主从复制

  • slave 通过 PSYNC 从 master 同步数据
  • 支持全量同步(RDB)和增量同步(replication backlog)

哨兵(Sentinel)

  • 监控主从、自动故障转移、通知客户端

Cluster 集群

  • 数据分片:16384 个哈希槽slot = CRC16(key) % 16384
  • 去中心化,节点间用 Gossip 协议通信
  • 支持在线扩缩容(槽迁移)