Chapter 01

Redis 核心概念与架构

理解 Redis 为何如此之快——单线程模型、内存数据结构与持久化设计

Redis 是什么

Redis(Remote Dictionary Server)是一个开源的内存数据结构存储系统,由 Salvatore Sanfilippo(antirez)于 2009 年创建。它不仅仅是一个缓存——Redis 支持丰富的数据结构,可作为数据库、缓存、消息代理和流处理引擎使用。

Redis 的核心特征是:所有数据存储在内存中,读写延迟通常在 0.1 毫秒级别,单节点可轻松达到 10 万+ QPS

Redis 的三种主要角色 ┌─────────────────────────────────────────────────────┐ │ Redis │ │ │ │ ┌───────────┐ ┌───────────────┐ ┌────────────┐ │ │ │ 缓存层 │ │ 数据库 │ │ 消息队列 │ │ │ │ │ │ │ │ │ │ │ │ 热点数据 │ │ 用户 Session │ │ 任务队列 │ │ │ │ API 缓存 │ │ 计数器/排行榜 │ │ 事件流 │ │ │ │ 页面缓存 │ │ 配置信息 │ │ 发布订阅 │ │ │ └───────────┘ └───────────────┘ └────────────┘ │ └─────────────────────────────────────────────────────┘

单线程模型:为何如此之快

很多人对 Redis 的第一个疑问是:"单线程怎么可能这么快?" 这是一个核心设计决策,理解它需要先明白性能瓶颈在哪里。

传统多线程服务器的问题

Redis 单线程 + I/O 多路复用

Redis 的快来自于:数据在内存中,I/O 是瓶颈而非 CPU。单线程完全避免了锁竞争,加上 epoll/kqueue 事件驱动模型,可以同时处理数万个连接。

Redis 事件循环模型 客户端连接池 Redis 单线程事件循环 ┌─────────┐ ┐ ┌─────────────────────────┐ │ Client1 │ │ TCP连接 │ epoll/kqueue 多路复用 │ │ Client2 │ │─────────────▶ │ ┌───────────────────┐ │ │ Client3 │ │ │ │ 就绪事件队列 │ │ │ ... │ ┘ │ │ [cmd1, cmd2, ...] │ │ └─────────┘ │ └────────┬──────────┘ │ │ │ 逐个处理 │ │ ▼ │ │ ┌────────────────────┐ │ │ │ 命令执行(内存op) │ │ │ └────────────────────┘ │ └─────────────────────────┘

Redis 6.0+ 引入多线程 I/O:网络数据的读取和写回使用多线程(默认关闭),但命令执行仍然是单线程。这进一步提升了网络 I/O 密集场景的性能,同时保持了命令执行的简单性。

内存数据结构总览

Redis 支持 5 种基础数据类型,每种类型在不同场景下使用不同的底层编码,以节省内存。

类型底层编码切换条件典型用途
Stringint / embstr / raw整数 / ≤44字节 / >44字节缓存、计数器
Hashlistpack / hashtable元素≤128 且值≤64字节对象存储
Listlistpack / quicklist元素≤128 且值≤64字节消息队列、时间线
Setlistpack / hashtable元素≤128 且均为整数标签、去重
ZSetlistpack / skiplist元素≤128 且值≤64字节排行榜、权重队列

Redis 7.0 更新:ziplist 被 listpack 全面替换。listpack 解决了 ziplist 的连锁更新问题(cascade update),在头部插入元素不再会导致整个结构重新分配。

持久化选项

Redis 是内存数据库,进程重启数据会丢失。为此提供了三种持久化方案:

Redis 7.x 新特性

Redis 7.0(2022年)

Redis 7.2(2023年)

与 Memcached 对比

Redis 和 Memcached 是两大主流内存缓存系统,选型时需要了解差异:

特性RedisMemcached
数据类型String/Hash/List/Set/ZSet/Stream/...仅 String(key-value)
持久化RDB + AOF不支持
集群原生 Cluster客户端分片
事务MULTI/EXEC + Lua不支持
发布订阅支持(PubSub / Stream)不支持
内存效率稍低(维护数据结构元信息)更高(简单 slab 分配)
线程模型单线程命令 + 多线程 I/O多线程
适用场景缓存/锁/队列/排行榜等复杂场景纯粹高性能缓存

快速安装与启动

# macOS(Homebrew)
brew install redis
brew services start redis

# Ubuntu / Debian
sudo apt update && sudo apt install redis-server
sudo systemctl start redis

# Docker(最方便)
docker run -d \
  --name redis7 \
  -p 6379:6379 \
  -v redis-data:/data \
  redis:7-alpine \
  redis-server --appendonly yes

# 验证连接
redis-cli ping     # 应输出 PONG
redis-cli info server | grep redis_version

redis-cli 基础操作速查

命令说明
redis-cli进入交互式命令行
redis-cli -h host -p port -a password连接远程 Redis
redis-cli ping测试连通性,返回 PONG
redis-cli info查看服务器信息
redis-cli monitor实时监控所有命令(慎用于生产)
redis-cli --bigkeys扫描大 key
redis-cli --latency测量服务延迟
SELECT n切换数据库(0-15,默认 0)
DBSIZE当前数据库 key 数量
FLUSHDB清空当前数据库(危险!)

生产环境禁用 KEYS *KEYS pattern 命令会阻塞 Redis 直到扫描完所有 key,在百万级 key 的生产库上执行可能导致服务超时。应使用 SCAN 命令替代,它以游标方式分批扫描,不会阻塞。

Python 连接示例

import redis

# 连接 Redis(使用连接池)
pool = redis.ConnectionPool(
    host='localhost',
    port=6379,
    db=0,
    decode_responses=True   # 自动将 bytes 解码为 str
)
r = redis.Redis(connection_pool=pool)

# 基础操作
r.set('name', 'Redis')
print(r.get('name'))       # 'Redis'
print(r.ping())            # True
print(r.info('server')['redis_version'])  # '7.x.x'