Redis 是什么
Redis(Remote Dictionary Server)是一个开源的内存数据结构存储系统,由 Salvatore Sanfilippo(antirez)于 2009 年创建。它不仅仅是一个缓存——Redis 支持丰富的数据结构,可作为数据库、缓存、消息代理和流处理引擎使用。
Redis 的核心特征是:所有数据存储在内存中,读写延迟通常在 0.1 毫秒级别,单节点可轻松达到 10 万+ QPS。
单线程模型:为何如此之快
很多人对 Redis 的第一个疑问是:"单线程怎么可能这么快?" 这是一个核心设计决策,理解它需要先明白性能瓶颈在哪里。
传统多线程服务器的问题
- 线程切换开销:每次上下文切换需要保存/恢复 CPU 寄存器状态,微秒级开销
- 锁竞争:多线程访问共享数据需要加锁,竞争激烈时吞吐量反而下降
- 内存同步:CPU 缓存一致性协议带来额外开销
Redis 单线程 + I/O 多路复用
Redis 的快来自于:数据在内存中,I/O 是瓶颈而非 CPU。单线程完全避免了锁竞争,加上 epoll/kqueue 事件驱动模型,可以同时处理数万个连接。
Redis 6.0+ 引入多线程 I/O:网络数据的读取和写回使用多线程(默认关闭),但命令执行仍然是单线程。这进一步提升了网络 I/O 密集场景的性能,同时保持了命令执行的简单性。
内存数据结构总览
Redis 支持 5 种基础数据类型,每种类型在不同场景下使用不同的底层编码,以节省内存。
| 类型 | 底层编码 | 切换条件 | 典型用途 |
|---|---|---|---|
| String | int / embstr / raw | 整数 / ≤44字节 / >44字节 | 缓存、计数器 |
| Hash | listpack / hashtable | 元素≤128 且值≤64字节 | 对象存储 |
| List | listpack / quicklist | 元素≤128 且值≤64字节 | 消息队列、时间线 |
| Set | listpack / hashtable | 元素≤128 且均为整数 | 标签、去重 |
| ZSet | listpack / skiplist | 元素≤128 且值≤64字节 | 排行榜、权重队列 |
Redis 7.0 更新:ziplist 被 listpack 全面替换。listpack 解决了 ziplist 的连锁更新问题(cascade update),在头部插入元素不再会导致整个结构重新分配。
持久化选项
Redis 是内存数据库,进程重启数据会丢失。为此提供了三种持久化方案:
-
RDB
快照(Snapshot):在指定时间点将内存数据以二进制格式写入
.rdb文件。恢复速度快,但可能丢失最近一次快照后的数据。适合备份。 -
AOF
追加写日志(Append Only File):将每条写命令以文本形式追加到
.aof文件。数据安全性高(最多丢失1秒数据),但文件较大,恢复慢。 - 混合模式 RDB + AOF(推荐):Redis 4.0+ 引入。AOF 文件头部是 RDB 格式的全量数据,尾部是增量 AOF 日志。兼顾恢复速度和数据安全。
Redis 7.x 新特性
Redis 7.0(2022年)
- Multi-Part AOF:AOF 文件分拆为多个部分,减少重写时的内存压力
- listpack 替换 ziplist:更高效的紧凑型内存结构
- ACL v2:更细粒度的权限控制,支持 key 级别的读写分离
- 函数(Functions):服务器端脚本管理,替代 Lua eval 的最佳实践
Redis 7.2(2023年)
- SINTERCARD:返回集合交集的基数,无需返回全部元素
- LMPOP / ZMPOP:从多个 key 中弹出元素
- EXPIRETIME / PEXPIRETIME:获取 key 的绝对过期时间戳
- Sharded Pub/Sub:Cluster 模式下的分片发布订阅,解决全量广播问题
与 Memcached 对比
Redis 和 Memcached 是两大主流内存缓存系统,选型时需要了解差异:
| 特性 | Redis | Memcached |
|---|---|---|
| 数据类型 | 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'