《Redis 开发与运维》学习笔记[特殊字符]
第 1 章 初识 Redis
1. Redis 核心特性(8 个维度)
速度快:纯内存存储,单线程命令处理,避免磁盘 IO 和上下文切换开销。
键值对数据结构:支持 string、hash、list、set、zset 5 种核心结构,适配多样业务场景。
功能丰富:包含持久化、主从复制、事务、Lua 脚本、发布订阅等功能。
简单稳定:代码简洁(核心代码约 2 万行),版本迭代兼容性强。
多客户端语言支持:Java、Python、Go 等主流语言均有成熟客户端库。
持久化:支持 RDB 快照和 AOF 日志两种持久化方式,保障数据可靠性。
主从复制:实现数据多节点备份,提升读性能与可用性。
高可用与分布式:Redis Cluster 提供分片和故障自动转移能力。
2. 适用与不适用场景
适用场景:热点数据缓存、会话存储、分布式锁、限流、排行榜、地理位置服务等。
不适用场景
:
冷数据存储(Redis 是内存数据库,存储冷数据成本高)。
超大规模数据(单机内存容量有限,虽可集群但复杂度上升)。
强事务 + 强一致性业务(Redis 事务不支持回滚,Cluster 弱一致性)。
3. 最佳实践
开发运维结合 + 读源码:通过阅读 Redis 源码(如单线程事件循环、数据结构实现),深入理解其原理;运维侧关注监控、持久化、集群稳定性。
生产环境启动方式
:通过配置文件
redis.conf
启动,示例核心配置:
conf
daemonize yes # 后台启动 port 6379 # 端口 bind 0.0.0.0 # 允许外部访问 loglevel notice logfile "/var/log/redis/redis.log"
版本选择:优先选择稳定版本(如 5.x、6.x),避免使用最新实验版,减少线上风险。
4. 里程碑版本
Redis 3.0 推出Redis Cluster,是官方首个分布式解决方案,支持数据分片、节点故障自动转移,为 Redis 大规模集群部署提供基础。
第 2 章 Redis 数据结构与内部编码
1. 5 种核心数据结构与内部编码
| 数据结构 | 内部编码(示例) | 适用场景 |
|---|---|---|
| string | raw(普通字符串)、int(整数)、embstr(短字符串) | 缓存、计数器、Session 存储 |
| hash | ziplist(短哈希)、hashtable(大哈希) | 存储对象(如用户信息) |
| list | ziplist(短列表)、linkedlist(长列表) | 消息队列、最新列表 |
| set | intset(整数集合)、hashtable(普通集合) | 标签、去重场景 |
| zset | ziplist(短有序集合)、skiplist(跳表 + 字典) | 排行榜、延迟任务 |
2. 高性能的三大支柱
纯内存存储:数据直接在内存中操作,读写速度比磁盘 IO 快数个数量级。
IO 多路复用:通过
epoll(Linux)等机制,单线程同时处理多个客户端连接的 IO 事件,避免阻塞。单线程架构:命令处理无需上下文切换,避免多线程竞争锁的开销;但需保证命令执行时间短,否则会阻塞整个服务。
3. 单线程命令处理机制
Redis 所有命令在主线程中串行执行,因此:
需避免执行耗时命令(如
keys *、hgetall 大哈希),否则会阻塞其他请求。复杂业务建议通过 Lua 脚本或 Pipeline 批量处理,减少网络往返。
4. 批量操作的效率优化
命令示例
:
mget key1 key2 key3:批量获取多个 string 值,减少多次get的 RTT(往返时间)。mset key1 val1 key2 val2:批量设置多个 string 值。hmset hashKey field1 val1 field2 val2:批量设置 hash 字段。
注意事项:批量操作的键 / 字段数量不宜过多(建议≤1000),否则会因单次命令耗时过长导致阻塞。
5. 命令时间复杂度与风险
| 命令 | 时间复杂度 | 风险场景 |
|---|---|---|
keys * | O(N) | 数据量大时阻塞整个 Redis |
hgetall | O(H) | 大 hash 全量读取阻塞 |
smembers | O(S) | 大 set 全量读取阻塞 |
zrange | O(logN+M) | 大 zset 全量范围读取阻塞 |
优化建议:用
scan替代keys,hscan替代hgetall,分段读取大集合。
6. 过期时间命令
persist key:移除任意类型键的过期时间,使其永久有效。set key value:设置 string 键时,会覆盖原有过期时间(开发时易忽视,需注意)。
7. 键迁移方案对比
| 方案 | 命令格式 / 原理 | 适用场景 | 局限性 |
|---|---|---|---|
| move | move key db(将键移到指定数据库) | 单机多库迁移 | 仅支持单机,已基本废弃 |
| dump+restore | dump key(序列化键)→ restore key ttl value(反序列化) | 跨实例迁移单键 | 非原子操作,需手动保证一致性 |
| migrate | migrate host port key destKey ttl [COPY] [REPLACE] | 跨实例原子迁移、Cluster 扩容 | 依赖目标实例可用性 |
migrate 优势:原子性执行 dump+restore,支持批量迁移(通过
KEYS参数),是 Redis Cluster 水平扩容的核心工具。
8. 渐进式遍历命令(scan 系列)
解决
keys命令阻塞问题,通过游标(cursor) 分批次遍历键空间。命令示例
:
bash
# 遍历所有键,每次返回10个,直到游标返回0 scan 0 match * count 10 # 遍历hash字段 hscan hashKey 0 match * count 5 # 遍历set元素 sscan setKey 0 match * count 5 # 遍历zset元素 zscan zsetKey 0 match * count 5
第 3 章 Redis 进阶操作
1. 慢查询分析
核心参数
:
slowlog-log-slower-than:慢查询阈值(单位:微秒),默认 10000(10 毫秒)。slowlog-max-len:慢查询日志最大长度,默认 128,超出后覆盖最早记录。
配置方式
:在
redis.conf
中设置,或通过命令动态修改:
bash
config set slowlog-log-slower-than 20000 config set slowlog-max-len 256
注意事项:慢查询仅记录命令执行时间,不包含网络传输和排队时间;需定期将慢查询日志持久化(如写入数据库),便于问题追溯。
2. 运维工具与命令
redis-cli 实用选项
:
--latency:测试 Redis 服务端延迟,示例:redis-cli --latency -h 127.0.0.1 -p 6379。--bigkeys:扫描大键(大 string、大 hash、大 list 等),示例:redis-cli --bigkeys。-i(间隔)+-r(次数):批量执行命令,示例:redis-cli -r 5 -i 1 ping(每 1 秒执行一次 ping,共 5 次)。
redis-benchmark 性能测试
:
示例:测试 127.0.0.1:6379 的读性能,并发 50,请求 10000 次:
bash
redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000 -t get
3. Pipeline 批量执行
作用:将多个命令打包发送,减少客户端与服务端的 RTT 次数,提升吞吐量。
命令示例
(以 Java Jedis 客户端为例):
java
运行
Pipeline pipeline = jedis.pipelined(); for (int i = 0; i < 100; i++) {pipeline.set("key" + i, "val" + i); } pipeline.sync(); // 同步执行所有命令注意事项:Pipeline 命令数不宜过多(建议≤500),否则会因单次网络包过大导致延迟上升。
4. Lua 脚本原子性执行
优势:将多个命令封装为 Lua 脚本,Redis 会原子性执行整个脚本,避免并发冲突。
执行方式
:
eval
:直接执行 Lua 脚本字符串,示例:
bash
eval "return redis.call('get','key1')" 0evalsha
:先通过
script load
加载脚本得到 sha1 值,再通过 sha1 执行,避免重复传输脚本:
bash
script load "return redis.call('get','key1')" evalsha <sha1> 0
应用场景:分布式锁(如 Redlock 实现)、复杂业务逻辑原子化执行。
5. Bitmaps 内存高效统计
命令示例
:
记录用户登录(用户 ID 为偏移量):
setbit login:20251028 10086 1(用户 10086 当天登录)。统计登录用户数:
bitcount login:20251028。获取用户登录状态:
getbit login:20251028 10086。
内存计算:存储 N 个用户的状态,仅需
N/8字节(如 1 亿用户仅需约 12MB),但setbit大偏移量(如 10 亿)会因申请连续内存导致阻塞。
6. HyperLogLog 基数统计
命令示例
:
新增访问用户:
pfadd uv:20251028 user1 user2 user3。统计独立用户数:
pfcount uv:20251028。合并多个统计集:
pfmerge uv:202510 uv:20251028 uv:20251029。
特性:统计 100 万独立元素仅需约 12KB 内存,误差率约 0.81%,适合 UV 统计等场景。
7. 发布订阅机制
命令示例
:
订阅频道:
subscribe news sports。发布消息:
publish news "Redis发布订阅示例"。订阅模式:
psubscribe news:*(订阅所有 news 开头的频道)。
局限性:无消息持久化、无堆积能力、无消费确认,仅适合简单通知场景(如实时消息推送),复杂消息队列建议用 RabbitMQ、Kafka。
8. GEO 地理位置服务
命令示例
:
添加地理位置:
geoadd cities 116.40 39.90 "北京" 121.47 31.23 "上海"。计算距离:
geodist cities 北京 上海 km(单位:km、m、mi、ft)。附近地点查询:
georadius cities 116.40 39.90 100 km withdist withcoord count 5(查询北京 100 公里内的 5 个地点,带距离和坐标)。
底层实现:基于 zset 存储,将经纬度编码为 score,通过跳表实现范围查询。
编辑分享
