运维常见题-Redis维护
DeepSeek V4 Flash 辅助生成。为确保内容的可靠性,笔者已对大部分关键论点进行了人工复核与校验。但鉴于大模型的固有局限,本文仍可能存在认知偏差或未尽准确之处。若您在阅读中发现存疑或矛盾之处,欢迎反馈讨论,笔者将及时核实与修正。🤔 Redis 有哪些应用场景?
Redis 作为高性能内存数据库/缓存,应用场景:①缓存(最核心:热点数据加速)②分布式锁(setnx/Redlock)③消息队列/发布订阅(轻量)④计数器/限流(incr)⑤排行榜/最新列表(ZSET/LIST)⑥会话共享(Session)⑦延迟任务/布隆过滤器等。核心:Redis 适合"高性能 + 简单数据结构"的场景,不适合海量存储/强一致事务。
- ① 缓存(最核心)
- 热点数据缓存:降低数据库压力、加速读取(最常见场景)
- 缓存模式:Cache Aside(旁路)/穿透/击穿/雪崩防护
- ② 分布式锁
SETNX+ 过期时间 实现锁(多个服务竞争锁)- 进阶:Redlock(多节点锁,防单点)
- ③ 消息队列/发布订阅
LIST(阻塞队列)/Pub/Sub(发布订阅)——轻量 MQ(可靠场景用专业 MQ)
- ④ 计数器/限流
INCR原子自增(计数器:点击量/库存);限流(令牌桶/滑动窗口)
- ⑤ 排行榜/最新列表
ZSET(有序集合):排行榜、按分数排序LIST:最新列表(时间线)
- ⑥ 会话共享(Session)
- 多台应用共享 Session(登录态),Redis 存会话
- ⑦ 其他
- 延迟任务(生产用 ZSet:score=时间戳,过期 key 通知不可靠仅限非严格场景)、布隆过滤器(缓存穿透)、分布式 ID、位图(签到/统计)
- 适用边界
- 适合:高并发读/简单数据结构/要求低延迟
- 不适合:海量数据(内存贵)、强一致事务(Redis 非事务强一致)、复杂查询
- ① 缓存(最核心)
协助记忆
- Redis 场景口诀:“缓存加速、锁防并发、队列解耦、计数器、排行榜、Session 共享”。
- 一句话:“高性能简单数据结构的场景用 Redis,复杂/海量/强一致交给 DB”。
进阶思考
- 缓存穿透、击穿、雪崩分别是什么(高频面试)?
- 穿透:查不存在的数据(缓存没有+DB 也没有)→ 每次都打 DB。防:布隆过滤器/缓存空值。
- 击穿:热点 key 过期瞬间大量请求打 DB。防:互斥锁/热点 key 不过期。
- 雪崩:大量 key 同时过期 → 大量请求打 DB。防:过期时间加随机、多级缓存、限流降级。
- 为什么 Redis 适合做分布式锁?
- 原子操作(
SETNX+ 过期)+ 高性能 + 简单(多服务共享):能实现"同一时刻只有一个服务能拿到锁"。注意:锁要带过期时间(防死锁)、释放要验证(防误删他人锁,用 Lua)。
- 原子操作(
- Redis 能当主力数据库吗?
- 看场景:缓存/简单结构可(Redis 也支持持久化);但海量数据/复杂查询/强事务场景不适合(内存贵、功能不如 DB)。主流定位:“缓存加速层”,数据可靠存储仍靠 DB。
- 缓存穿透、击穿、雪崩分别是什么(高频面试)?
扩展信息
- Redis 生态周边:Redis 支持模块(BloomFilter/JSON/TimeSeries)、Redis 做缓存 vs 专业 MQ(可靠投递:Kafka/RocketMQ)、版本演进(ACL 权限控制 6.0 引入、Redis Functions 函数 7.0 引入)
- 缓存一致性模式:Cache Aside(旁路缓存,主流)、Read/Write Through、Write Behind——了解前两者即可(面试常考)
- Redis 与其他键值存储对比:Memcached(纯缓存无持久化/数据结构单一)、Redis(数据结构丰富+持久化)——Redis 更全能
🤔 Redis 单进程为啥还这么快?
Redis 单进程(单线程)仍快的原因:①纯内存操作(内存读写远快于磁盘)②I/O 多路复用(单线程高效处理大量连接)③高效数据结构(底层为专门优化的结构)④避免锁开销/线程切换(单线程无竞争)⑤非阻塞 I/O + 事件循环。核心:“内存快 + 多路复用不浪费 + 单线程无锁开销”。
- ① 纯内存操作(根本)
- 数据在内存(读写 ns 级,远快于磁盘 ms 级)——速度快的基础
- 持久化(
BGSAVE/AOFeverysec等后台路径)异步,不阻塞主流程(SAVE同步/AOFalways会阻塞,需避免)
- ② I/O 多路复用(高并发关键)
- 单线程用
epoll(Linux 多路复用)同时监听大量连接 - 多个连接事件轮询处理(非阻塞 I/O),不用每连接一个线程
- 处理大量并发连接的能力(数万 QPS 的前提)
- 单线程用
- ③ 高效数据结构(底层优化)
- 每种数据类型底层用专门结构(SDS 动态字符串、跳表、压缩列表等)
- 操作大多 O(1)/O(log n),高效
- ④ 单线程无锁/无切换开销
- 单线程避免:锁竞争(多线程要加锁)、线程上下文切换开销
- 命令串行执行(天然线程安全,无需锁)
- ⑤ 事件循环模型
- 单线程事件循环:接收事件(连接/命令)→ 依次处理
- 非阻塞(处理快的命令不拖慢其他)
- 注意(单线程的代价)
- 单条命令耗时长会阻塞其他命令(慢命令/大 key/
KEYS *是坑) - 6.0 引入多线程处理网络 I/O(但命令执行仍是单线程)
- 单条命令耗时长会阻塞其他命令(慢命令/大 key/
- ① 纯内存操作(根本)
协助记忆
- 单线程快 = “内存快(基础)+ 多路复用(不浪费)+ 无锁(无开销)"。
- 一句话:“内存里的操作本来就快,多路复用让它能扛高并发,单线程免了锁的开销”。
进阶思考
- 为什么单线程反而不比多线程慢(甚至更快)?
- 多线程有锁竞争/上下文切换/CPU 缓存失效开销;Redis 命令简单(内存操作极快),单线程串行足够快,且避免了这些开销。Redis 瓶颈常在网络/内存而非 CPU(单线程 CPU 不是瓶颈)。
- 什么操作会让 Redis “卡”(阻塞单线程)?
- 慢命令:
KEYS *(全键扫描)、SMEMBERS大集合、大 key 操作、SAVE(同步持久化)、BGREWRITEAOF大文件、删除大 key(新版异步删除UNLINK解决)。生产要避免这些(或异步化)。
- 慢命令:
- 6.0 多线程改了什么(不是全多线程)?
- 6.0 用多线程处理"网络 I/O”(读/写 socket),但命令执行仍是单线程——多线程加速了网络吞吐(尤其大并发连接),命令处理逻辑不变(保持简单/无锁)。多线程 I/O 是可配置的(
io-threads)。
- 6.0 用多线程处理"网络 I/O”(读/写 socket),但命令执行仍是单线程——多线程加速了网络吞吐(尤其大并发连接),命令处理逻辑不变(保持简单/无锁)。多线程 I/O 是可配置的(
- 为什么单线程反而不比多线程慢(甚至更快)?
扩展信息
- I/O 多路复用对比:select/poll/epoll(Linux epoll 最高效,事件驱动)——理解"单线程如何高并发"的关键
- Redis 数据结构底层(简单了解):SDS(字符串)、链表/压缩列表、跳表(ZSET)、哈希表——每个数据类型有专门底层实现(高效)
- 异步删除:
UNLINK(异步删大 key)/FLUSHALL ASYNC——4.0 引入,解决大 key 删除阻塞
🤔 Redis 支持哪些数据类型?
Redis 支持的数据类型:①String(字符串)②List(列表)③Hash(哈希)④Set(集合)⑤ZSet(有序集合)⑥Bitmap(位图)⑦HyperLogLog(基数统计)⑧GEO(地理位置)⑨Stream(流,7.0 起)。核心:五大数据类型(String/List/Hash/Set/ZSet)必答,其余按场景补充。
- 五大基础类型(必答)
String(字符串):最基础,存字符串/数字/JSON;命令GET/SET/INCRList(列表):有序列表,可做队列/栈/时间线;LPUSH/RPUSH/LRANGEHash(哈希):键值对集合(对象存储:用户信息);HSET/HGET/HGETALLSet(集合):无序不重复,做去重/交集并集;SADD/SMEMBERS/SINTERZSet(有序集合):带分数排序的集合,做排行榜/优先级;ZADD/ZRANGE/ZRANK
- 高级类型(按需补充)
Bitmap(位图):位操作(签到/在线状态/统计);SETBIT/GETBIT/BITCOUNTHyperLogLog(基数统计):去重计数(UV 统计,误差小省内存);PFADD/PFCOUNTGEO(地理位置):经纬度存储/距离计算;GEOADD/GEODISTStream(流):消息流(5.0 引入,7.0 增强消费者组/ACK);XADD/XREAD
- 场景对应
- String:缓存/计数器;List:队列/时间线;Hash:对象/会话
- Set:去重/标签;ZSet:排行榜/排序;Bitmap:签到/位图统计
- HyperLogLog:UV;GEO:附近的人;Stream:消息
- 命令前缀记忆
- 类型命令前缀:String(
GET/SET)、List(L开头)、Hash(H)、Set(S)、ZSet(Z)、Bitmap(BIT)、HLL(PF)、GEO(GEO)、Stream(X)
- 类型命令前缀:String(
- 五大基础类型(必答)
协助记忆
- 五大类型口诀:“字符串(String)、列表(List)、哈希(Hash)、集合(Set)、有序集合(ZSet)"。
- 命令前缀记忆:“L 列表、H 哈希、S 集合、Z 有序、BIT 位、PF 基数、X 流”。
进阶思考
- 各类型底层数据结构(面试加分)?
- String→SDS;List→快速列表;Hash→哈希表/压缩列表;Set→整数集合/哈希表;ZSet→跳表+哈希表——了解"为什么快/内存省”(底层为场景优化的结构)。
- String 存对象和 Hash 存对象怎么选?
- String(JSON 整体存):简单、整体读写(适合不常改部分字段的对象);Hash(字段独立):可只改某字段(适合常改字段、省内存——大对象 Hash 更省)。按"是否常改部分字段"选。
- ZSet 的"分数"能做什么(不止排行榜)?
- 分数可做:排行榜(分数=得分)、延迟任务(分数=时间戳)、优先级队列、限流(分数=时间窗口)。“有序 + 按分数操作"让它很灵活。
- 各类型底层数据结构(面试加分)?
扩展信息
- 底层数据结构速查:SDS(字符串)、quicklist(列表)、listpack/ziplist(紧凑)、intset(整数集合)、skiplist(跳表,ZSet)、dict(哈希表)——面试常问"Redis 快/省内存的底层"题
- 类型 vs 底层:数据类型(逻辑)≠ 底层结构(物理),Redis 按数据规模自动选择底层(如 listpack vs hashtable)
- 进阶能力:Lua 脚本(原子多命令)、Pipeline(批量)、事务(MULTI/EXEC)——组合数据类型做复杂逻辑
🤔 Redis 内存回收(淘汰)策略有哪些?
Redis 内存回收分两类:①过期删除策略(key 到期的处理)②内存淘汰策略(内存满时删哪些 key)。核心:①过期删除:惰性删除 + 定期删除(主动+被动结合);②内存淘汰:
maxmemory-policy配置(noeviction/allkeys-lru/volatile-lru等),生产一般用allkeys-lru或volatile-lru。- ① 过期删除策略(key 到期怎么删)
- 惰性删除:key 被访问时检查是否过期,过期则删(省资源,但过期 key 可能占内存)
- 定期删除:定期(每 100ms)抽样检查部分过期 key 删除(主动清理)
- 结合:惰性(被动)+ 定期(主动)——折中(不实时全删,但避免堆积)
- ② 内存淘汰策略(内存满时 maxmemory-policy)
noeviction(默认):内存满不淘汰,会导致内存增长的写命令报错(DEL/UNLINK等删除类命令仍允许)allkeys-lru:所有 key 按 LRU(最少最近使用)淘汰——生产常用volatile-lru:仅设了 TTL 的 key 按 LRU 淘汰(无 TTL 的 key 不参与;若都无 TTL 则该策略退化为不淘汰)allkeys-random/volatile-random:随机淘汰(所有/仅设 TTL 的 key)volatile-ttl:按剩余 TTL 短的淘汰(仅设 TTL 的 key)allkeys-lfu/volatile-lfu:按 LFU(最少使用频率)淘汰(Redis 4.0+)
- 怎么配置
maxmemory(内存上限,如 2gb)+maxmemory-policy(策略)- 生产:设
maxmemory(防内存无限涨)并选淘汰策略
- 选择建议
- 缓存场景:
allkeys-lru(淘汰不常用 key,保留热点)或volatile-lru(只对有过期时间的 key 淘汰) - 不能丢数据(如持久化重要):
noeviction(满了报错,人工处理)但会影响业务
- 缓存场景:
- ① 过期删除策略(key 到期怎么删)
协助记忆
- 内存回收两件事:“过期删除(惰性+定期)“与"内存淘汰(maxmemory-policy)"。
- 策略口诀:“noeviction 不淘汰(报错)、LRU 少用淘汰、LFU 频用保留”。
进阶思考
- 惰性删除和定期删除为什么"结合"用?
- 只惰性:过期 key 不被访问就永远占内存(堆积);只定期:每次要扫很多(开销大)。惰性(被访问才删)+ 定期(周期抽扫):主动清掉不活跃的过期 key,又不大开销——折中方案。
- LRU 和 LFU 区别(怎么选)?
- LRU(最近最少使用):看"多久没被访问”(适合缓存:不常用淘汰);LFU(最不经常使用):看"访问频率”(适合:频率低淘汰,防"偶尔访问一次的热点被误淘汰”)。一般缓存用 LRU 够,需抗"突发访问"用 LFU。
- 为什么生产一定要设 maxmemory?
- 不设 = 内存无限增长:数据一直加,内存耗尽 → OOM(进程被系统杀)或无限 swap(性能崩)。设 maxmemory + 策略:内存满时"有策略地淘汰"(可控),而非系统崩溃。
- 惰性删除和定期删除为什么"结合"用?
扩展信息
- 内存淘汰与过期删除的关系:过期 key 先被"过期删除"处理;“内存淘汰"是内存满时对未过期 key 的处理(两者独立)
- LRU 实现:Redis 的 LRU 是"近似 LRU”(抽样 5 个取最久,非全量),兼顾效率与效果
- 相关命令:
CONFIG GET maxmemory/INFO memory(看内存)、keyspace监控
🤔 Redis 两种持久化 RDB 和 AOF 有什么区别及优缺点?
Redis 持久化两种:RDB(快照)和 AOF(追加日志),区别:①RDB 存"某一时刻的数据快照"(二进制,恢复快、体积小,但可能丢最后一次快照后的数据);②AOF 存"每一条写命令"(文本,数据更完整,但文件大、恢复慢)。核心:“RDB 快照省空间快恢复但丢数据,AOF 全量命令不丢但开销大”;生产常用两者结合(RDB 快照 + AOF 增量),7.0 起 AOF 合并为单一文件。
- RDB(快照持久化)
- 存什么:某一时刻的数据库快照(二进制文件
dump.rdb) - 触发:
SAVE(同步)/BGSAVE(后台异步)/配置自动(save 900 1等) - 优点:①文件小(二进制压缩)②恢复快(直接加载快照)③性能影响小(BGSAVE 后台 fork)
- 缺点:①可能丢数据(快照间隔间的写会丢,如 5 分钟一次丢 5 分钟)②
BGSAVEfork 消耗内存/大实例 fork 慢
- 存什么:某一时刻的数据库快照(二进制文件
- AOF(追加日志)
- 存什么:每一条写命令(追加到
appendonly.aof) - 触发:按策略刷盘(
appendfsync always/everysec/no) - 优点:①数据完整(按策略最多丢 1 秒/不丢)②可读/可修复(文本命令)
- 缺点:①文件大(所有命令累积)②恢复慢(重放所有命令)③写性能影响(要刷盘)
- 存什么:每一条写命令(追加到
- 对比
维度 RDB AOF 存储 快照(数据) 命令日志 体积 小 大(可重写) 恢复 快 慢 丢数据 可能(间隔间) 少(按策略) 写性能 好 略差(刷盘) - 7.0 AOF 变化
- AOF 改为"多部分 AOF"(manifest + base/incr 段),对外呈现单一逻辑文件;自动 rewrite(
auto-aof-rewrite-*)早于 7.0 已有
- AOF 改为"多部分 AOF"(manifest + base/incr 段),对外呈现单一逻辑文件;自动 rewrite(
- 最佳实践(结合使用)
- 生产:RDB(快照备份/快速恢复)+ AOF(增量不丢)——两者结合
- 另:混合持久化(
aof-use-rdb-preamble,AOF 文件含 RDB 头做基础,启动加载快;7.0 起默认开启)——是"RDB 头 + AOF 增量"的文件格式,与"RDB 和 AOF 双开"是两个概念
- RDB(快照持久化)
协助记忆
- 对比口诀:“RDB 快照(小/快/丢间隔数据)、AOF 日志(全/重/少丢),生产结合用”。
- 一句话:“想省心用 RDB 快恢复,想不丢用 AOF 全记录,最好两个都要”。
进阶思考
- 为什么 RDB 会丢数据?怎么减少?
- RDB 是"定时快照":两次快照之间的写不落盘,进程挂/断电丢这段时间数据。减少:缩短快照间隔(如
save 60 1000)或用 AOF 补增量。要更不丢用 AOF。
- RDB 是"定时快照":两次快照之间的写不落盘,进程挂/断电丢这段时间数据。减少:缩短快照间隔(如
- AOF 文件越来越大怎么办(rewrite)?
- AOF 累积所有命令 → 文件大、恢复慢 →
AOF rewrite(BGREWRITEAOF):重写成"当前数据的最新命令"(瘦身)——7.0 自动管理(单一文件)。生产要定期/自动 rewrite。
- AOF 累积所有命令 → 文件大、恢复慢 →
- Redis 持久化和"缓存数据丢了无所谓"矛盾吗?
- 不矛盾:Redis 可纯缓存(重启丢缓存,从 DB 重建)也可持久化(数据重要才持久化)。生产常"Redis 持久化开启"(防重启全丢缓存/避免缓存雪崩重建风暴)。按数据重要性决定持久化强度。
- 为什么 RDB 会丢数据?怎么减少?
扩展信息
- 持久化配置:
save(RDB 触发)、appendonly yes/appendfsync(AOF 开关/刷盘)、auto-aof-rewrite-*(自动重写) - 混合持久化(4.0+):RDB 做基础快照 + AOF 做增量(重启加载快+RDB 后重放 AOF)——两者结合的优势,生产推荐
- 数据恢复:重启时若配置持久化,自动从 RDB/AOF 加载(有 AOF 优先 AOF——更全);备份用 RDB/AOF 文件 + 定期备份
- 运维:
INFO persistence看持久化状态、redis-check-aof修复损坏 AOF
- 运维:
- 持久化配置:
🤔 Redis 内存持续飙升,该如何排查?
Redis 内存飙升排查:①看内存统计(
INFO memory/redis-cli --stat)②分析内存构成(MEMORY USAGE/MEMORY DOCTOR/大 key)③定位原因(数据增长/大 key/碎片/过期 key 堆积/内存淘汰未生效)④解决(删大 key/优化数据结构/设 maxmemory+淘汰/碎片整理/过期清理)。核心:“先看内存统计→定位大 key/异常→清理与限制”。- 第一步:看内存统计
INFO memory:used_memory(实际使用)、used_memory_human、used_memory_rss(进程占用,含碎片)used_memory_rss远大于used_memory→ 内存碎片redis-cli --stat(实时看内存/QPS)
- 第二步:定位大 key/内存大户
MEMORY USAGE <key>(单 key 内存)、MEMORY DOCTOR(诊断建议)- 大 key 扫描:
redis-cli --bigkeys(找大 key) KEYS *不推荐(阻塞),用SCAN遍历- 按类型看:Hash/List/ZSet 大集合是内存大户
- 第三步:分析原因(为什么会涨)
- 数据持续写入(业务增长/缓存未过期)
- 大 key(单 key 内存巨大:大 List/Hash/字符串)
- 内存碎片(
mem_fragmentation_ratio高:增删多导致) - 过期 key 堆积(惰性删除没清、定期删除慢)
- 未设
maxmemory(无限增长,最终 OOM) - 慢命令/连接数(连接也占内存)
- 第四步:解决
- 删大 key:
UNLINK(异步删除,不阻塞)、拆分大 key(数据分片) - 设 maxmemory + 淘汰策略:防无限增长(
allkeys-lru等) - 过期清理:调定期删除频率/检查过期 key 是否堆积
- 碎片整理:
memory purge/activedefrag(自动碎片整理,4.0+) - 优化数据结构:压缩/精简(如 Hash 用 field 而非多个 String)
- 容量:必要时扩容/数据分层(冷数据落 DB)
- 删大 key:
- 第一步:看内存统计
协助记忆
- 内存排查口诀:“INFO 看统计、MEMORY 查大户、找大 key(bigkeys)、设 maxmemory、清碎片/过期”。
- 一句话:“先看数据还是碎片,再定位大 key/未限制,删/限/清”。
进阶思考
- 内存碎片怎么来的?怎么解决?
- 频繁增删数据(内存分配/释放不连续)→ 碎片(
used_memory_rss>used_memory)。解决:activedefrag yes(自动碎片整理)或重启(清碎片)、memory purge(手动)。碎片严重会导致 RSS 涨但数据没涨多少。
- 频繁增删数据(内存分配/释放不连续)→ 碎片(
- 大 key 为什么危险?
- ①占内存(单 key 巨大)②操作阻塞(大 key 的
GET/DEL/遍历会卡单线程)③影响其他请求。定位:--bigkeys扫描 +MEMORY USAGE;删除用UNLINK(异步)避免阻塞。
- ①占内存(单 key 巨大)②操作阻塞(大 key 的
- 没设 maxmemory 会怎样?
- 内存无限涨 → 系统 OOM(Redis 被杀)或疯狂 swap(性能崩)——Redis 直接不可用。生产必设
maxmemory+ 淘汰策略(可控地处理内存满),并监控内存水位(如 80% 告警)。
- 内存无限涨 → 系统 OOM(Redis 被杀)或疯狂 swap(性能崩)——Redis 直接不可用。生产必设
- 内存碎片怎么来的?怎么解决?
扩展信息
- 内存相关命令速查:
INFO memory、MEMORY USAGE key、MEMORY DOCTOR、MEMORY PURGE、redis-cli --bigkeys、CONFIG GET maxmemory - 内存优化思路:数据结构精简(Hash 聚合)、设置
maxmemory、过期清理、碎片整理、数据分层(热 Redis/冷 DB)、容量规划 - 监控水位:内存使用率告警(70%/80%/90% 分级),防 OOM
- 内存相关命令速查:
🤔 使用 Redis INFO 命令查看哪些关键指标?
Redis
INFO命令按段返回运行信息,关键指标分几块:①server(版本/运行时间)②memory(内存:used_memory/maxmemory/碎片)③stats(QPS/命中率/连接/keyspace)④clients(连接数)⑤persistence(持久化状态)⑥replication(主从状态)⑦cpu(CPU 使用)。核心:监控内存、命中率、连接、持久化、主从几个关键段。- INFO 分段说明
INFO(全部)/INFO memory(只某段)/INFO server等
- 关键段与指标
memory(内存,最关键):used_memory(使用内存)、used_memory_human、used_memory_rss(进程内存,看碎片)、mem_fragmentation_ratio(碎片率,结合used_memory绝对量级判断:小实例数据量小时碎片率天然偏高,大实例 >1.5 才需关注)、maxmemory(上限)、used_memory_peak(历史峰值)stats(统计):total_connections_received/total_commands_processed(QPS 相关)、keyspace_hits/keyspace_misses(命中/未命中→命中率)、rejected_connections(被拒连接)clients(连接):connected_clients(当前连接)、blocked_clients(阻塞连接)、maxclients(上限)persistence(持久化):rdb_last_bgsave_status(上次保存状态)、aof_enabled、aof_last_write_status、aof_rewrite_in_progressreplication(主从):role(master/slave)、connected_slaves(从库数)、master_link_status(主从连接)、slave_repl_offset(复制偏移)cpu:used_cpu_sys/used_cpu_user(CPU 使用)server:redis_version(版本)、uptime_in_seconds(运行时间)
- 怎么用(监控)
redis-cli info/INFO memory——人工查看- 监控采集:
redis_exporter(Prometheus)采集 INFO 指标 - 关键告警:内存、命中率、连接数、主从断开、持久化失败
- INFO 分段说明
协助记忆
- INFO 关键段口诀:“内存(used_memory/碎片)、统计(命中率/QPS)、连接(clients)、持久化(aof/rdb)、主从(role/offset)"。
- 一句话:“INFO 里盯内存、命中、连接、持久化、主从这五块”。
进阶思考
- 命中率怎么算(低了说明什么)?
- 命中率 =
keyspace_hits / (keyspace_hits + keyspace_misses)。低命中率 = 大量 key 未命中(缓存没生效/穿透/过期)——说明缓存效率差,要查(数据过期快/穿透)。
- 命中率 =
mem_fragmentation_ratio(碎片率)怎么看?- =
used_memory_rss / used_memory:>1.5 说明碎片严重(要整理/重启);<1 说明有 swap(内存不足,危险)。正常 1~1.5。
- =
- 连接数指标怎么用(
connected_clients)?- 连接数接近
maxclients→ 连接耗尽(新连接被拒:rejected_connections涨)→ 查连接泄漏(客户端没关连接)/连接池不足。监控连接数 + 被拒数告警。
- 连接数接近
- 命中率怎么算(低了说明什么)?
扩展信息
- INFO 全量段:Server/Clients/Memory/Persistence/Stats/Replication/CPU/Commandstats/Cluster/Keyspace——按需用
INFO <section> - 监控工具:
redis_exporter(Prometheus)、redis-cli --stat、云 Redis 监控(有内置指标) - 关键阈值参考:内存 >80% maxmemory 告警、命中率 <90% 关注、碎片率 >1.5 处理、连接接近 maxclients 告警
- INFO 全量段:Server/Clients/Memory/Persistence/Stats/Replication/CPU/Commandstats/Cluster/Keyspace——按需用
🤔 简述 Redis 主从复制工作原理?
Redis 主从复制(Master-Slave Replication):主库(Master)负责写,从库(Slave/Replica)从主库复制数据,实现读写分离与数据冗余。原理:①全量复制(初次:主库生成 RDB 快照给从库+后续命令)②增量复制(运行中:主库把写命令发给从库同步)③offset/积压缓冲区(断线续传)。核心:“主库写、从库读,全量+增量同步,断线续传”。
- 作用
- 读写分离(主写从读,分担读压力)、数据冗余(从库备份)、故障切换基础
- 全量复制(初次/断线无法增量)
- 从库连接主库 → 主库
BGSAVE生成 RDB → 发送给从库 → 从库加载 - 加载期间主库新写的命令先缓存(replication buffer)→ 加载完补发
- 适用:初次建立/断线太久(积压缓冲区已覆盖不了)
- 从库连接主库 → 主库
- 增量复制(运行中持续)
- 主库每写一条命令 → 发给从库(propagate)→ 从库执行(保持同步)
- 依赖:复制偏移量(offset)+ 积压缓冲区(backlog,记录最近命令)
- 断线续传(部分重同步 PSYNC)
- 从库断线重连 → 带自己的 offset +
master_replid→ 主库校验 replid 一致且积压缓冲区还有这些命令 - 满足 → 从断点增量补发(部分重同步,高效);不满足(offset 超出 backlog 或 replid 不一致/换过复制链)→ 全量重来
- 从库断线重连 → 带自己的 offset +
- 关键配置/概念
- 从库:
replicaof <master-ip> <port>(或SLAVEOF) master_replid(复制 ID)、repl_offset(偏移量)、repl-backlog-size(积压缓冲区大小)- 主从数据:
master_link_status:up/down(连接状态)
- 从库:
- 注意
- 默认异步复制(从库可能短暂落后)、从库只读(默认
replica-read-only yes) - 全量复制对大实例有开销(RDB 生成+传输)
- 默认异步复制(从库可能短暂落后)、从库只读(默认
- 作用
协助记忆
- 主从复制 = “主库写,从库跟着同步:先全量(快照)+后增量(命令),断线从断点续传”。
- 口诀:“全量起步、增量持续、offset 续传”。
进阶思考
- 全量复制和增量复制什么时候用?
- 初次/长期断线(积压区覆盖不了)→ 全量(RDB 快照+补命令);运行中断线短(积压区还有)→ 增量(从断点补)。增量高效(不重新传全部数据),全量开销大(大实例尽量少触发)。
repl-backlog-size(积压缓冲区)设多大?- 决定"断线多久还能增量续传”:积压区越大能容忍断线越久(且内存开销越大)。按"网络稳定性 + 写入量"设(写入快/断线久 → 设大些,避免频繁全量复制)。
- 主从复制会不会丢数据?
- 默认异步:主库写完可能还没同步到从库,主库挂 → 从库缺最近写入(短暂丢)。注意:哨兵/Cluster 的故障转移仍是异步复制(只降低故障影响,不保证不丢);真正提供"写确认"语义的是
WAIT/同步复制(但性能降)。“异步默认 + 可配更可靠”。
- 默认异步:主库写完可能还没同步到从库,主库挂 → 从库缺最近写入(短暂丢)。注意:哨兵/Cluster 的故障转移仍是异步复制(只降低故障影响,不保证不丢);真正提供"写确认"语义的是
- 全量复制和增量复制什么时候用?
扩展信息
- 命令:
REPLICAOF/SLAVEOF(设置主从)、INFO replication(看状态)、redis-cli --replicaof - 复制类型:全量同步(RDB)、增量同步(命令流)、部分重同步(offset 断点续传)——三类
- 演进:
REPLICAOF命令/replicaof配置自 Redis 5.0 起启用(SLAVEOF降为别名);INFO replication的connected_slaves/slave_repl_offset字段当前版本仍用 slave 命名(官方术语迁移尚未完成)
- 命令:
🤔 Redis 主从复制延迟过高怎么解决?
Redis 主从复制延迟(从库数据滞后于主库)原因:①网络延迟/带宽(主从传输慢)②从库处理慢(大命令/从库负载高)③主库写入量大(同步跟不上)④积压缓冲区太小(触发全量)。解决:网络优化、减从库负载、
repl-backlog-size调大、主库写入分担、监控延迟。- 常见原因
- 网络:主从跨机房/带宽不足(传输慢)
- 从库负载高:从库跑重查询/慢命令(处理命令慢)
- 主库写入量大:写命令多,同步跟不上
- 大命令/大 key:单条命令复制慢(大 key 传输)
- 积压缓冲区小:断线后无法增量(触发全量复制,更慢)
- 同步复制写阻塞:配了
WAIT等从库确认——增加的是主库写响应延迟(与“从库滞后”机理不同,属写延迟口径)
- 查看延迟
INFO replication:看master_repl_offset和slave_repl_offset差(偏移量差 = 滞后量)、slave_repl_lag- 注:
redis-cli --latency测的是客户端→服务端 RTT,非主从复制滞后,勿混用
- 解决方法
- 网络优化:主从同机房/同区域、带宽充足、专线
- 从库减负:从库别跑重查询(或加只读副本)、别让从库做持久化太重
- 积压缓冲区调大:
repl-backlog-size调大(减少全量复制) - 主库写入分担:主库写压力大 → 分片(Cluster)/应用优化
- 避免大命令/大 key:拆大 key(复制快)
- 监控延迟:偏移量差告警(超过阈值处理)
- 核心
- 复制延迟是"同步速度跟不上写入速度":要么加快同步(网络/从库),要么减少写入(分片),要么允许一定延迟(异步本质)
- 常见原因
协助记忆
- 延迟解决口诀:“网络优化(同机房)、从库减负、backlog 调大、主写分片、避免大 key”。
- 一句话:“同步跟不上了就提速(网络/从库)或减量(分片/去大key)"。
进阶思考
- 怎么"量化"复制延迟(不只看感觉)?
- 对比
master_repl_offset(主库)和slave_repl_offset(从库)差值 → 主从数据差多少(字节/命令数);再换算时间(写入速率)。持续监控偏移差告警。
- 对比
- 为什么"大 key"会加剧复制延迟?
- 大 key 的操作(如大集合增删)产生大命令/大量数据:主库执行快、复制传输/从库执行慢 → 从库被这个大命令拖住(滞后)。避免大 key 或拆小。
- 复制延迟对业务影响?能不能容忍?
- 影响:从库读到旧数据(读一致性);故障切换时丢最近写(主挂切从,缺延迟数据)。容忍度看业务(读延迟敏感/写重要)——严格场景用半同步/
WAIT;Cluster 降低丢写靠min-replicas-to-write配置。
- 影响:从库读到旧数据(读一致性);故障切换时丢最近写(主挂切从,缺延迟数据)。容忍度看业务(读延迟敏感/写重要)——严格场景用半同步/
- 怎么"量化"复制延迟(不只看感觉)?
扩展信息
- 延迟相关:
master_repl_offset/slave_repl_offset(偏移差)、INFO replication、积压缓冲区(backlog) - 主从架构演进:主从复制 → 哨兵(加自动故障切换)→ Cluster(分片+副本)——延迟/高可用逐步增强
- 读一致性取舍:异步复制(从库可能旧)vs 半同步(
WAIT保证不丢但慢)——按业务权衡
- 延迟相关:
🤔 Redis 高可用方案有哪些?
Redis 高可用方案(由简单到复杂):①主从复制(基础:数据冗余/读写分离,但主库故障需手动切换)②哨兵模式 Sentinel(在主从基础上加自动故障切换/监控,生产标配)③Redis Cluster(分片+副本+自动故障转移,支持大数据量/多节点)。核心:“主从是基础,哨兵加自动切换,Cluster 加分布式扩展”。
- ① 主从复制(基础高可用)
- 主写从读(读写分离)+ 数据冗余(从库备份)
- 局限:主库故障不会自动切换(需人工 promote 从库)——不算完整高可用
- 适用:读写分离/简单冗余(故障切换容忍人工)
- ② 哨兵模式(Sentinel,生产标配高可用)
- 在主从基础上加 Sentinel(哨兵):监控主从、自动故障转移、通知客户端
- 主库故障 → 哨兵自动选新主(从库 promote)+ 客户端感知
- 优点:自动故障切换(秒级~分钟级)、无需人工
- 适用:中小规模需要自动高可用(单主多从)
- 局限:单主写(写无扩展)
- ③ Redis Cluster(分布式高可用)
- 分片(多主节点各自管数据)+ 副本 + 自动故障转移
- 优点:写扩展(多主分片)+ 高可用(副本自动切换)+ 大数据量(水平扩展)
- 适用:大数据量/高写入/多节点集群
- 局限:运维复杂、跨槽操作受限(多 key 操作要在同槽)
- 选型
- 简单冗余:主从;自动高可用(中小):哨兵;大数据量/扩展:Cluster
- 云 Redis:云厂商托管(自带高可用,省心)
- ① 主从复制(基础高可用)
协助记忆
- 高可用三档:“主从(基础冗余)→ 哨兵(自动切换)→ Cluster(分布式扩展)"。
- 一句话:“要自动切换用哨兵,要扩展用 Cluster,简单冗余用主从”。
进阶思考
- 哨兵和 Cluster 怎么选(核心区别)?
- 哨兵:单主多从(一个写节点,自动切换主)——适合"写不大/数据量适中"需要高可用;Cluster:多主分片(多写节点)——适合"写大/数据多"需要扩展。哨兵解决"高可用”,Cluster 解决"高可用+扩展”。
- 哨兵集群本身怎么保证高可用?
- Sentinel 也要多节点(一般 3+,奇数):多个哨兵互相监控 + 投票决定故障(防单哨兵误判)。哨兵数要"多数派"(3 节点容忍 1 故障)——哨兵不是单点。
- 高可用方案的"故障切换会丢数据吗"?
- 取决于复制模式:异步复制下主库挂 → 切换的新主可能缺最近未同步数据(短暂丢)。要更可靠:
WAIT/半同步或 Cluster 的副本多数派——权衡可用性与一致性。
- 取决于复制模式:异步复制下主库挂 → 切换的新主可能缺最近未同步数据(短暂丢)。要更可靠:
- 哨兵和 Cluster 怎么选(核心区别)?
扩展信息
- 高可用方案对比:主从(人工切换)、哨兵(自动切换,单写)、Cluster(分片+自动,多写)、云 Redis(托管高可用)
- 哨兵 vs Cluster 演进:Redis 官方推荐大数据量/生产用 Cluster;哨兵适合中小/已有主从架构升级
- 故障切换代价:切换有秒级~分钟级不可用窗口(哨兵检测+选主)、数据可能短暂丢失(异步)——高可用方案是"权衡"非"完美""
🤔 什么是 Redis 哨兵模式 (Sentinel)?
Redis 哨兵模式(Sentinel)是在主从复制基础上加"哨兵进程"实现自动高可用:哨兵监控主从状态,主库故障时自动选新主(提升从库)并通知客户端。核心:“哨兵 = 监控 + 自动故障转移 + 通知”,实现 Redis 主从的自动切换(无需人工)。
- 是什么(定义)
- 在主从(Master-Replica)基础上部署 Sentinel 进程(哨兵)
- 哨兵职责:监控(主从健康)、自动故障转移(主挂选新主)、通知(告知客户端新主)
- 解决主从"主库挂了不会自动切换"的问题(人工切换)
- 哨兵核心功能
- 监控:定期 ping 主从(判断存活)
- 故障转移(Failover):主库故障 → 选一个从库提升为新主 → 其他从库改从新主
- 通知:把新主信息告诉客户端/其他哨兵
- 配置提供:客户端可从哨兵获取当前主节点
- 工作原理(故障转移流程)
1 2 3 4 51. 哨兵监控主库(ping 心跳) 2. 主库不可达 → 哨兵标记主观下线(sentinel 主观判断) 3. 多个哨兵确认 → 客观下线(quorum 配置确认,防误判;触发转移还需哨兵间 majority 选举 leader) 4. 哨兵 leader 按规则(优先级/偏移量/runid)选定从库 → 提升为新主(promote;从库按规则选定,非投票产生) 5. 其他从库改从新主、通知客户端 → 高可用恢复 - 哨兵集群(自身高可用)
- Sentinel 多节点部署(3+,奇数):互相监控 + 投票(多数派决策,防单哨兵误判)
- 哨兵挂了不影响已运行的主从(但故障转移依赖哨兵存活)
- 配置
sentinel monitor <master-name> <ip> <port> <quorum>(定义监控的主)sentinel.conf(哨兵配置)
- 与主从区别
- 主从:数据复制(无自动切换);哨兵:主从 + 自动故障转移(高可用)
- 是什么(定义)
协助记忆
- 哨兵 = “主从的自动管家”:看着主从(监控),主挂了自动换(选新主),并告诉大家(通知)。
- 口诀:“监控 + 自动故障转移 + 通知,主挂秒换新主”。
进阶思考
- 哨兵怎么判断主库"真挂了"(防误判)?
- 单哨兵标记主观下线(SDOWN)→ 达到 quorum 数哨兵确认客观下线(ODOWN)→ 哨兵间 majority 选举 leader → 才触发故障转移。防"一个哨兵误判/网络抖动就切换"。
- 哨兵选新主的依据(怎么选从库)?
- 官方选主顺序:①
slave-priority(数值小优先,0 不参与)②复制偏移量最大(数据最全)③runid 最小。优先选"数据最接近主库"的从库(少丢数据)。
- 官方选主顺序:①
- 故障转移会丢数据吗?
- 可能:异步复制下主库挂时未同步到从库的数据丢失(切换的新主缺这部分)。要少丢:
WAIT/半同步或接受短暂丢——高可用与数据一致性权衡。
- 可能:异步复制下主库挂时未同步到从库的数据丢失(切换的新主缺这部分)。要少丢:
- 哨兵怎么判断主库"真挂了"(防误判)?
扩展信息
- 哨兵 vs Cluster(定位):哨兵解决"单主高可用"(一个写节点自动切换);Cluster 解决"多主扩展+高可用"(分片)。中小规模高可用用哨兵,大数据量/扩展用 Cluster。
- 配置要点:
quorum(客观下线所需哨兵数)、down-after-milliseconds(判定下线时间)、failover-timeout(转移超时) - 演进:Redis 官方趋势——大数据量/新项目更多用 Cluster;哨兵适合已有主从架构/中小规模
🤔 哨兵模式 (Sentinel) 下应用程序如何连接?
哨兵模式下应用连接:不是直连主节点(IP 会因故障切换变化),而是连哨兵(Sentinel)获取当前主节点地址,再连主节点。实现:①客户端用哨兵地址 + master-name,通过 Sentinel API 获取主节点②监听哨兵通知(切换时自动重连新主)③官方客户端(如 Java Redis 客户端)内置 Sentinel 支持。 核心:“应用连哨兵拿主节点,故障切换后自动获知新主”。
- 为什么不能直连主节点
- 主节点 IP 会变(故障切换后新主是原来的从库,地址不同)
- 直连旧 IP → 切换后连不上(服务中断)
- 应用连接方式(Sentinel 模式)
- 应用配置:Sentinel 地址(
sentinel节点 IP/端口)+ 主节点名(mymaster) - 连接流程:应用 → 连任一哨兵 → 问"当前主节点是谁"(
SENTINEL get-master-addr-by-name)→ 拿主节点地址 → 连接主节点读写 - 故障切换:哨兵通知/客户端重新查询 → 应用自动连到新主(无需改配置)
- 应用配置:Sentinel 地址(
- 客户端支持
- 主流客户端内置 Sentinel:Java(
Jedis/Lettuce)、Python(redis-py)、Go(go-redis)等 - 配置方式:客户端传入 Sentinel 节点列表 + masterName(如 Jedis
JedisSentinelPool)
- 主流客户端内置 Sentinel:Java(
- 示例(概念)
1 2 3 4// Jedis Sentinel 配置(概念) Set<String> sentinels = { "sentinel1:26379", "sentinel2:26379" }; JedisPool pool = new JedisSentinelPool("mymaster", sentinels); // 获取连接时 Jedis 会向哨兵查询当前主节点 - 核心
- 应用"面向哨兵 + 主节点名",不面向具体 IP——故障切换对应用透明(自动重连新主)
- 为什么不能直连主节点
协助记忆
- 哨兵连接 = “应用问哨兵’主在哪’(master-name),哨兵告诉它,切主后自动换”。
- 一句话:“连哨兵拿主节点,别写死 IP,切换自动适应”。
进阶思考
- 为什么用"master-name"而不是 IP?
- IP 会变(切换后新主地址不同);master-name(如 mymaster)是逻辑名:哨兵知道"mymaster 当前对应哪台"——应用只认名字,地址由哨兵动态给(解耦)。
- 故障切换时应用会中断吗?
- 会短暂中断(切换期间旧主不可用、新主提升有秒级窗口):客户端会报错/超时,切换完成后自动连新主恢复。应用要做重试/连接池,接受短暂中断(哨兵高可用是"秒级切换"不是"零中断")。
- 哨兵本身怎么连(应用配置多个哨兵)?
- 应用配多个哨兵地址(哨兵集群):一个哨兵挂了连其他——哨兵本身高可用(多数派)。应用连任意一个能用的哨兵即可拿到主节点信息。
- 为什么用"master-name"而不是 IP?
扩展信息
- 哨兵相关命令:
SENTINEL get-master-addr-by-name <name>(查主)、SENTINEL masters(看主列表)、SENTINEL monitor(配置) - 客户端配置:Sentinel 节点列表 + masterName(主流客户端均支持);切换后客户端自动重连(客户端内置订阅哨兵通知/重新查询)
- 与 Cluster 连接对比:哨兵(面向 master-name 连单主);Cluster(面向任一节点,客户端用 cluster 协议路由到分片)——连接方式不同
- 哨兵相关命令:
🤔 简述 Redis Cluster 工作原理?
Redis Cluster 是分布式集群:把数据按"槽位(16384 个 slot)“分片到多个主节点(每个主节点管一段槽),客户端按 key 哈希路由到对应节点,每个主节点可有副本(从节点)实现高可用,主节点故障自动转移到副本。核心:“槽位分片 + 客户端路由 + 副本自动故障转移”,实现写扩展与高可用。
- 核心概念
- 槽位(Slot):16384 个槽(
0~16383),数据按 key 的CRC16哈希对 16384 取模分到某槽 - 主节点分片:每个主节点负责一段槽(如 3 主节点各 5000+ 槽)——数据分布在不同节点
- 副本(Replica):每个主节点可有从节点(副本)备份 + 故障接管
- 槽位(Slot):16384 个槽(
- 工作原理
1 2 3 41. 写 key → 计算 key 的槽(CRC16(key) % 16384)→ 定位负责该槽的主节点 2. 客户端连对节点:若连错(槽在其他节点)→ 返回 MOVED 重定向 → 客户端跳到正确节点 3. 主节点有副本:主挂 → 副本自动提升为新主(故障转移) 4. 客户端按槽路由(cluster 客户端内置槽-节点映射) - 关键机制
- CRC16 哈希槽:key 定位槽(
HASH_SLOT = CRC16(key) % 16384) - MOVED/ASK 重定向:
MOVED= 槽归属已变的永久重定向(客户端须更新并缓存槽映射,再访问);ASK= 槽迁移中的临时重定向(仅对单条命令有效、不缓存,需先发 ASKING)——两者语义不同勿混 - 故障转移:主节点故障(多数派确认)→ 从副本提升为新主(类似哨兵机制,Cluster 内置)
- 集群总线(cluster bus):节点间通信(gossip 传播状态)
- CRC16 哈希槽:key 定位槽(
- 数据访问注意
- 多 key 操作(MGET/MSET 跨槽)会失败——除非用 hash tag(
{user}相同标签同槽)
- 多 key 操作(MGET/MSET 跨槽)会失败——除非用 hash tag(
- 部署
- 至少 3 主节点(生产 3 主 + 每主副本,如 6 节点)
- 端口:客户端端口 + 10000 = 集群总线端口(如 7000→17000,bus 端口默认 +10000)
- 核心概念
协助记忆
- Cluster = “槽位分片”:16384 槽按 key 哈希分到多主,客户端按槽路由,副本自动接管故障。
- 口诀:“CRC16 分槽、MOVED 路由、副本故障转移、多 key 要同槽(hash tag)"。
进阶思考
- 为什么用"16384 个槽”(不是无限分)?
- 固定槽数(16384)便于:槽-节点映射(节点增减只需迁移槽,不用全量重hash)、路由信息小(心跳带槽位图)。16384 是兼顾"分片粒度"和"路由信息大小"的平衡。
- MOVED 重定向是什么(客户端怎么应对)?
- 客户端请求的槽不在该节点 → 返回
MOVED <slot> <ip:port>指向正确节点——客户端缓存槽-节点映射后直接访问(不用每次重定向)。集群客户端(cluster 模式)内置该逻辑。
- 客户端请求的槽不在该节点 → 返回
- Cluster 的"多 key 操作"为什么受限?
- 多 key 在不同槽(不同节点)就无法原子操作(如 MGET 跨节点)。解决:hash tag(
{user}:orders和{user}:cart同{user}同槽)——把相关 key 放同槽。设计时注意。
- 多 key 在不同槽(不同节点)就无法原子操作(如 MGET 跨节点)。解决:hash tag(
- 为什么用"16384 个槽”(不是无限分)?
扩展信息
- Cluster 与哨兵/主从对比:主从(单写)、哨兵(单写+自动切换)、Cluster(多写分片+自动故障)——规模/扩展递增
- 哈希槽 vs 一致性哈希:Cluster 用固定槽(CRC16%16384),与 Memcached 一致性哈希不同(固定槽迁移/路由更可控)
- 常用命令:
CLUSTER INFO/CLUSTER SLOTS(看槽分布)、redis-cli -c(集群模式自动重定向)
🤔 Redis Cluster 集群不可用的常见原因及解决方案?
Redis Cluster 不可用原因:①槽分配不均/槽迁移失败②主节点故障且无可用副本(副本不足)③多数派节点故障(无法选出新主)④网络分区(脑裂/节点失联)⑤客户端路由问题(连错/MOVED 没处理)⑥配置错误(槽覆盖/重复)。解决:槽均衡/迁移修复、保证副本数、检查多数派/网络、客户端用集群模式、配置校验。
- ① 槽问题(槽迁移/分配)
- 槽分配不均(部分节点槽多压力大);槽迁移中(
CLUSTER SETSLOT/reshard 失败) - 槽没覆盖全(16384 槽未分配全 → 部分数据无主)
- 解决:
CLUSTER RESHARD(重新分槽)、检查槽覆盖(CLUSTER INFO的cluster_state)
- 槽分配不均(部分节点槽多压力大);槽迁移中(
- ② 主节点故障无副本
- 主节点挂了但无可用副本(副本也挂了/没配副本)→ 该主节点的槽不可用
- 解决:每主配副本(
cluster-require-full-coverage权衡)、补副本
- ③ 多数派节点故障
- 集群多数派节点不可达 → 无法选出新主(故障转移需多数派确认)
- 解决:保证集群多数派存活(容量/故障隔离)、快速恢复节点
- ④ 网络分区
- 节点间网络分区:少数派侧无法选举新主(多数派投票防长期双主);真正风险是少数派侧旧主在分区期间接收的写入,愈合后被丢弃(数据丢失)
- 解决:网络稳定、
cluster-node-timeout合理、监控集群状态
- ⑤ 客户端路由问题
- 客户端没用集群模式(连单节点、不处理 MOVED)→ 访问跨节点报错
- 解决:客户端用 cluster 模式(
redis-cli -c/客户端 cluster 支持)
- ⑥ 配置/部署错误
- 重复节点、配置不一致(“槽覆盖/两节点管同槽"是极端配置错误,正常
CLUSTER SETSLOT会拒绝,非常见故障) - 解决:检查
CLUSTER NODES/CLUSTER SLOTS,重新初始化(必要时重建集群)
- 重复节点、配置不一致(“槽覆盖/两节点管同槽"是极端配置错误,正常
- 排查命令
CLUSTER INFO(集群状态:cluster_state:ok/fail)、CLUSTER NODES(节点/槽/主从)、CLUSTER SLOTS(槽分布)- 日志/监控(节点故障、网络、重定向)
- ① 槽问题(槽迁移/分配)
协助记忆
- Cluster 不可用排查口诀:“看 CLUSTER INFO 状态、查槽分布(SLOTS)、检查副本(每主有备)、多数派存活、客户端集群模式”。
- 一句话:“槽没覆盖/主没副本/多数派挂了/客户端没集群模式——逐个查”。
进阶思考
cluster-require-full-coverage是什么(集群可用性权衡)?- 默认 yes:任一槽无主(某主+副本全挂)→ 整个集群拒绝服务(保数据一致,牺牲可用);设 no:有槽不可用但其他正常服务(保可用,部分数据不可访问)。按"一致性 vs 可用性"权衡。
- 脑裂怎么发生(网络分区)?
- 网络分区把集群分成两边:两边各自有主节点(互相认为自己是主)→ 写分散(数据分裂)。防:多数派(分区小的一边失去多数派无法提供写)、
cluster-node-timeout(超时判死)、监控网络。Cluster 靠多数派 + 超时防脑裂。
- 网络分区把集群分成两边:两边各自有主节点(互相认为自己是主)→ 写分散(数据分裂)。防:多数派(分区小的一边失去多数派无法提供写)、
- 槽迁移中请求会怎样?
- 槽迁移期间:请求可能返回
ASK(迁移中)或MOVED(已迁完)——客户端处理 ASK/MOVED 重定向(集群客户端内置)。迁移期间服务不中断(但要注意迁移完成确认)。
- 槽迁移期间:请求可能返回
扩展信息
- 集群健康检查:
CLUSTER INFO(cluster_state)、CLUSTER NODES(节点状态/槽)、redis-cli --cluster check(检查集群)、监控(节点数/槽分布/副本数) - 运维操作:加节点(
redis-cli --cluster add-node)、删节点、RESHARD(重分槽)、故障恢复(副本 promote) - 最佳实践:3 主 3 从起步、每主配副本、监控槽覆盖/多数派、客户端集群模式、网络稳定
- 集群健康检查:
🤔 Redis 阻塞、卡顿怎么处理?
Redis 阻塞/卡顿处理:①定位阻塞源(
SLOWLOG慢命令/LATENCY延迟/INFO状态)②常见阻塞源(慢命令 KEYS/大 key 操作/持久化 fork/SAVE同步/AOF 刷盘/内存 swap/网络)③针对性解决(避免慢命令、拆大 key、异步持久化、调参数)。核心:“先定位卡在哪(慢命令/持久化/内存),再对症(改命令/拆 key/调参)"。*- 第一步:定位阻塞
SLOWLOG GET(慢命令日志:看哪些命令耗时)LATENCY DOCTOR/LATENCY LATEST(延迟诊断,需先设latency-monitor-threshold>0 才有数据)INFO stats(latest_fork_usecfork 耗时)、INFO commandstats(各命令耗时)- 观察(
redis-cli --latency/-i实时)
- 第二步:常见阻塞源
- 慢命令:
KEYS *(全扫描)、SMEMBERS/HGETALL(大集合全取)、SORT大集合、ZRANGE大范围——单线程执行耗时,阻塞其他 - 大 key 操作:大 key 的
GET/DEL(删除大 key 阻塞)/遍历 - 持久化阻塞:
SAVE(同步快照阻塞)、BGSAVE大实例 fork(fork 阻塞)、AOFappendfsync always(每次写刷盘)、BGREWRITEAOF大 AOF - 内存问题:内存 swap(不足时换页极慢)、内存淘汰风暴(满时大量淘汰)
- 资源耗尽:磁盘 IOPS 打满(持久化写盘/大流量落盘)、CPU 满载(复杂命令/大并发)——整体变慢
- 网络:客户端慢(输出缓冲大/慢连接)——
client-output-buffer-limit
- 慢命令:
- 第三步:解决
- 避免慢命令:
KEYS *→SCAN;大集合分页/增量处理 - 拆大 key:大 List/Hash 拆分(减少单命令耗时);
UNLINK(异步删除大 key) - 持久化调优:用
BGSAVE(后台)别用SAVE;AOFeverysec(别 always);BGREWRITEAOF低峰执行 - 内存:设
maxmemory+ 淘汰策略、检查 swap(加内存) - 网络/缓冲:调大客户端输出缓冲/排查慢客户端
- 监控告警:延迟/慢命令告警(提前发现)
- 避免慢命令:
- 第一步:定位阻塞
协助记忆
- 阻塞排查口诀:“SLOWLOG 看慢命令、LATENCY 看延迟、KEYS 换 SCAN、大 key 拆/异步删、SAVE 换 BGSAVE”。
- 一句话:“单线程最怕慢命令和大 key,持久化别同步,内存别 swap”。
进阶思考
- 为什么单线程下"一个慢命令"能卡住整个 Redis?
- 单线程串行执行命令:一条命令耗时 N 秒,后面所有命令都等 N 秒(整库卡顿)。所以慢命令/大 key 是 Redis 大忌(执行时全局阻塞)。
- 大 key 删除为什么阻塞(UNLINK 解决)?
- 旧
DEL删除大 key:要遍历释放内存(耗时,阻塞单线程);UNLINK(异步删除):后台释放(不阻塞)——生产删大 key 用 UNLINK。
- 旧
BGSAVEfork 为什么会阻塞?BGSAVE要 fork 子进程(复制内存页表):大实例(几 GB)fork 可能耗时(数百 ms~秒级)阻塞——所以持久化/备份注意大实例的 fork 影响(低峰执行、监控 fork 耗时)。
- 为什么单线程下"一个慢命令"能卡住整个 Redis?
扩展信息
- 慢命令处理:
SLOWLOG(查看/配置)、KEYS *→SCAN(游标遍历)、大集合用分页/HSCAN/SSCAN/ZSCAN(增量) - 持久化阻塞优化:
BGSAVE后台、AOFeverysec(别 always 拖写)、大实例错峰持久化、副本承载备份 - 延迟排查工具:
redis-cli --latency(客户端视角延迟)、LATENCY DOCTOR(诊断)、监控(redis_exporter 延迟/命令耗时)
- 慢命令处理:
🤔 如何优化 Redis 的性能?
Redis 性能优化核心:①命令层(避免慢命令/大 key、用批量 Pipeline)②内存层(设 maxmemory、数据结构精简、防 swap)③持久化层(BGSAVE/异步、错峰)④网络层(连接池、客户端缓冲)⑤架构层(读写分离/Cluster 分片)。核心:“单线程下把慢命令/大 key/阻塞去掉,用批量与分片提吞吐”。
- ① 命令层优化(最直接)
- 避免慢命令:
KEYS *→SCAN;大集合用分页(HSCAN/SSCAN/ZSCAN) - 避免大 key:拆大 key(大 List/Hash 拆分)、
UNLINK异步删 - 批量:
Pipeline(批量发命令减少 RTT)、MGET/MSET - 合理过期:过期策略合理(防大量同过期雪崩,加随机)
- 避免慢命令:
- ② 内存层优化
- 设
maxmemory+ 淘汰策略(防内存无限涨/swap) - 数据结构精简:Hash 存对象(省内存)、用 listpack/紧凑结构
- 防 swap(内存不足换页极慢)——内存要够
- 碎片整理(
activedefrag)、MEMORY USAGE查大户
- 设
- ③ 持久化层优化
BGSAVE(后台)别SAVE(同步阻塞)- AOF
everysec(别 always 拖写) - 大实例持久化错峰(低峰执行)、副本承载备份
- ④ 网络/客户端优化
- 连接池(客户端复用连接,别每请求新连)
client-output-buffer-limit(防慢客户端拖垮)- Pipeline/批量(减网络往返)
- ⑤ 架构层优化
- 读写分离(主写从读,分担读压力)
- Cluster 分片(大数据量/写扩展)
- 客户端就近(同机房,减延迟)
- ⑥ 监控驱动
- 看
INFO(内存/命中率/命令耗时)、SLOWLOG(慢命令)、延迟监控 - 发现瓶颈针对性优化(内存/慢命令/网络)
- 看
- ① 命令层优化(最直接)
协助记忆
- 性能优化口诀:“命令(SCAN/批量/拆key)、内存(maxmemory/精简)、持久化(BGSAVE/错峰)、网络(连接池/批量)、架构(读写分离/分片)"。
- 一句话:“单线程怕慢命令,先清命令再管内存/网络/架构”。
进阶思考
- Pipeline 和 MGET 有什么不同(怎么选)?
- Pipeline:批量发多条命令(减少 RTT,命令可不同);
MGET:一次取多 key(减少 RTT + 单命令)。Pipeline 更通用(任意命令),MGET 是"取多 key"专用(更简洁)。批量是减 RTT 的关键(网络往返是常见开销)。
- Pipeline:批量发多条命令(减少 RTT,命令可不同);
- “大 key"怎么影响性能(为什么优先处理)?
- 大 key:①操作慢(遍历/传输大)②阻塞单线程(大 key 的 DEL/遍历卡住其他请求)③复制/迁移慢。优化优先:拆大 key(拆分/分片)——单线程下大 key 是"定时炸弹”。
- 性能瓶颈怎么判断是内存/CPU/网络?
- 看
INFO stats(QPS)、INFO memory(内存)、used_cpu_*(CPU)、延迟(–latency);大并发场景常用网络(RTT)瓶颈、大数据场景内存瓶颈、复杂命令场景 CPU 瓶颈——按指标定位。
- 看
- Pipeline 和 MGET 有什么不同(怎么选)?
扩展信息
- 性能工具:
redis-benchmark(压测)、SLOWLOG(慢命令)、redis-cli --latency(延迟)、INFO(指标)、监控(redis_exporter) - 参数调优:
maxmemory、maxmemory-policy、appendfsync、io-threads(6.0 网络多线程)、tcp-keepalive/连接超时 - 设计优化:数据结构选型(省内存)、key 设计(避免无谓的膨胀)、业务层缓存策略(缓存击穿/雪崩防护)
- 性能工具:
🤔 Redis 6.0 多线程有了解过吗?多线程作用?
Redis 6.0 引入多线程(默认关闭,需配置开启):用多线程处理"网络 I/O”(socket 读/写、命令解析),但命令执行仍是单线程。作用:①提升网络吞吐(高并发大连接时瓶颈在网络 I/O,多线程并行处理读写)②命令执行逻辑不变(保持单线程简单/无锁)③解决"高并发下的网络 I/O 瓶颈”(不是解决 CPU 计算瓶颈)。
- 为什么引入多线程(背景)
- Redis 瓶颈常在"网络 I/O”(高并发时读/写 socket 消耗 CPU),而非命令执行(命令简单)
- 单线程网络 I/O 在高并发连接下成瓶颈 → 6.0 用多线程并行处理网络 I/O
- 多线程做什么(作用)
- 网络 I/O 多线程:多条线程并行处理 socket 读/写、协议解析(accept/read/write)
- 命令执行仍单线程:命令在单线程顺序执行(保持无锁/简单/有序)
- 效果:网络吞吐提升(并发连接/大流量场景明显)
- 配置
io-threads(线程数,如 4/8)、io-threads-do-reads(是否读也多线程,默认写多线程)- 注意:默认关闭(单线程);线程数建议 < CPU 核数;只影响网络 I/O 路径
- 与"单线程快"的关系
- 之前"单线程快"因内存快+多路复用;6.0 多线程补"网络 I/O 并行”(网络是外部 I/O,不影响命令逻辑)
- 本质:“网络 I/O 并行 + 命令执行单线程”——兼顾吞吐与简单
- 注意(多线程不是万能)
- 只提升网络吞吐(大并发连接),不提升单命令性能(命令仍单线程串行)
- CPU 计算密集场景(复杂命令)多线程帮助有限
- 多线程有少量锁开销(网络层)——不是所有场景都更快
- 为什么引入多线程(背景)
协助记忆
- 6.0 多线程 = “网络 I/O 并行(多线程读写 socket),命令执行还是单线程”。
- 一句话:“多线程治网络吞吐瓶颈,命令逻辑保持单线程简单”。
进阶思考
- 为什么"命令执行"保持单线程(不一起多线程化)?
- 命令单线程:①无锁(数据无需并发保护,简单可靠)②有序(命令顺序执行,语义明确)③Redis 命令简单(内存操作快,CPU 不是瓶颈)。网络 I/O 才是瓶颈 → 只多线程网络层(不破坏命令执行的优势)。
- 多线程开启后会有副作用吗?
- 有:网络层加锁开销(小)、线程上下文切换;线程数配置不当(太多)反而降性能。且只对"网络吞吐瓶颈"场景有效(大并发连接),普通场景收益有限甚至负。按需开启(压测确认)。
- 6.0 多线程和"主从/集群复制"有关系吗?
- 无直接关系:多线程是单节点内网络 I/O 优化;主从/集群是架构层(多节点)。两者独立(多线程优化单节点吞吐,集群扩展总吞吐)。
- 为什么"命令执行"保持单线程(不一起多线程化)?
扩展信息
- Redis 版本演进(网络相关):1.x 单线程 → 6.0 网络 I/O 多线程(可选)→ 7.x 优化(如 I/O 线程改进)——演进方向"单线程命令 + 多线程 I/O"
- 相关配置:
io-threads(网络 I/O 线程数)、io-threads-do-reads(读多线程)、tcp-backlog/连接数 - 与 Memcached 对比:Memcached 多线程(处理 I/O + 命令);Redis 单线程命令 + 可选多线程 I/O——架构取舍不同
🤔 Redis 慢查询日志是什么?如何配置与使用?
Redis 慢查询日志(Slowlog)记录执行时间超过阈值的命令,用于排查慢命令/阻塞。配置:
slowlog-log-slower-than(阈值,如 10000 微秒=10ms)、slowlog-max-len(保留条数);使用:SLOWLOG GET(查看)、SLOWLOG LEN(条数)、SLOWLOG RESET(清空)。- 是什么
- Redis 记录"执行时间超过阈值"的命令(慢命令日志)
- 用途:定位慢命令(单线程下慢命令阻塞其他请求,必须发现)
- 配置参数
slowlog-log-slower-than:阈值(微秒),如 10000(10ms)以上记录;0 记录所有、负数关闭slowlog-max-len:最多保留多少条(默认 128,环形覆盖)- 配置:
CONFIG SET slowlog-log-slower-than 10000(运行时);持久化可CONFIG REWRITE(7.0+ 写回 redis.conf)或改redis.conf
- 使用命令
SLOWLOG GET(查看,可SLOWLOG GET 10看最近 10 条)SLOWLOG LEN(当前条数)SLOWLOG RESET(清空)
- 慢日志字段
- 每条含:ID、时间戳、执行耗时(微秒)、命令及参数、客户端地址
- 看
duration(耗时)判断哪些命令慢
- 怎么用(排查)
- 定期
SLOWLOG GET看慢命令(哪些命令/多少耗时) - 发现慢命令(如 KEYS *、大 key 操作)→ 优化(换 SCAN/拆 key)
- 监控慢日志(告警:慢命令增多说明有问题)
- 定期
- 是什么
协助记忆
- 慢查询日志 = “Redis 记’慢命令’的黑账”:超过阈值(slowlog-log-slower-than)就记录。
- 口诀:“阈值 slowlog-log-slower-than、保留 slowlog-max-len、查看 SLOWLOG GET”。
进阶思考
- 慢查询阈值设多少合适?
- 按业务延迟要求:高并发下 10ms 的单线程阻塞已明显拖慢业务,宜按延迟目标设 15ms(10005000 微秒);设太低会记太多(噪音)、太高漏掉影响。结合监控(延迟敏感度)调。
- 慢日志能看到什么(怎么定位问题命令)?
- 看
duration(耗时)+ 命令(哪条慢)——找到"阻塞源命令"。结合上下文(哪时段/哪客户端)定位。慢命令通常是:KEYS *、大 key 的遍历/删除、SORT大集合等。
- 看
- 慢日志和"阻塞"什么关系?
- 慢命令=执行慢(单线程下阻塞其他请求);慢日志就是"阻塞候选"的记录。持续有慢命令 → 会积累延迟/阻塞 → 必须处理(优化命令/拆 key)。慢日志是"提前发现阻塞源"的工具。
- 慢查询阈值设多少合适?
扩展信息
- 配置动态调整:
CONFIG SET slowlog-log-slower-than/slowlog-max-len(运行时生效,重启后失——要永久改 redis.conf) - 与其他诊断配合:
INFO commandstats(各命令累计耗时)、LATENCY DOCTOR(延迟诊断)、redis-cli --latency(客户端延迟) - 运维提示:慢日志也占内存(max-len 限制)、定期查看清理(
SLOWLOG RESET)
- 配置动态调整:
🤔 Redis 一般会监控哪些指标?
Redis 监控指标分几块:①可用性(
ping/连接)②内存(used_memory/碎片/峰值/淘汰量)③性能(QPS/命令耗时/慢命令)④命中率(keyspace_hits/misses)⑤连接(connected_clients/被拒)⑥持久化(RDB/AOF 状态)⑦复制(主从状态/延迟)。核心:“内存、命中率、连接、复制、持久化"五块必盯,配redis_exporter+ Prometheus。- 可用性
ping(通不通)、进程/实例存活、uptime
- 内存(最核心)
used_memory(使用内存)/used_memory_peak(峰值)/maxmemory(上限)mem_fragmentation_ratio(碎片率,结合used_memory绝对量级判断:小实例数据量小时碎片率天然偏高,>1.5 不一定异常;大实例 >1.5 才需关注)evicted_keys(淘汰 key 数,突然增多=内存压力)- 告警:内存使用率(70%/80%/90%)
- 性能
- QPS(
total_commands_processed速率)、命令耗时(INFO commandstats) SLOWLOG(慢命令数/时长)- 延迟(客户端视角
--latency)
- QPS(
- 命中率
keyspace_hits/keyspace_misses→ 命中率(hits/(hits+misses))- 命中率低 = 缓存效率差(穿透/过期)
- 连接
connected_clients(当前连接,接近 maxclients 告警)rejected_connections(被拒连接,连接耗尽)blocked_clients(阻塞连接,异常注意)
- 持久化
rdb_last_bgsave_status(RDB 状态)、aof_enabled/aof_last_write_status(AOF)- 持久化失败告警(欠持久化=数据风险)
- 复制(主从/集群)
role(主/从)、master_link_status(主从连接)slave_repl_offset差(复制延迟)、从库数- 集群:
cluster_state、节点数
- 实现
redis_exporter(Prometheus)采集 Redis 指标- Grafana 面板(Redis 官方/社区模板)
- 告警:内存/命中率/连接/复制/持久化/慢命令
- 可用性
协助记忆
- 监控五块:“内存(used_memory/碎片)、命中率、连接、复制(offset 差)、持久化(aof/rdb)"。
- 一句话:“redis_exporter 采指标,盯内存/命中/连接/复制/持久化五块”。
进阶思考
- 命中率低说明什么(怎么处理)?
- 命中率低 = 大量请求没命中缓存(打 DB):可能缓存穿透/数据过期快/缓存没建好。处理:查穿透(布隆/空值)、调过期、确认缓存逻辑。命中率是"缓存有效性"的关键指标。
evicted_keys突然增多意味着什么?- 淘汰 key 多 = 内存接近 maxmemory(触发淘汰):要么内存不够(扩容/清理),要么淘汰策略激进。持续淘汰会导致"缓存失效风暴”(大量 key 被淘汰→击穿 DB)——要关注。
- 复制延迟怎么监控(多主从/集群)?
- 主从:
master_link_status(连接)+ offset 差(滞后量);集群:cluster_state+ 各节点复制状态。复制断开/滞后告警(高可用风险)。
- 主从:
- 命中率低说明什么(怎么处理)?
扩展信息
- 监控栈:
redis_exporter(指标采集)+ Prometheus(存储/告警)+ Grafana(看板)——标准组合 - 关键告警示例:内存 >80%、命中率 <90%、连接接近 maxclients、主从断开、持久化失败、慢命令多
- 云 Redis 监控:云厂商自带监控(内存/连接/命中率等),可配告警
- 监控栈:
🤔 Redis 如何提高安全性?
Redis 提高安全性:①认证(
requirepass密码/ACL 用户权限)②网络隔离(不暴露公网/防火墙/绑定内网)③禁用危险命令(rename-command:FLUSHALL/KEYS/CONFIG等)④数据加密(TLS)⑤系统层(非 root 运行/最小权限)⑥防攻击(防暴力/未授权访问)。核心:“Redis 默认无认证,必须设密码 + 不暴露公网 + 禁危险命令”。- ① 认证(身份)
requirepass <password>:设置访问密码(所有连接需认证)- ACL(6.0+):更细粒度用户权限(每用户可访问 key/命令,
ACL SETUSER) - 生产必须设密码(Redis 默认无认证=裸奔)
- ② 网络隔离(访问控制)
- 不暴露公网:只在内网/防火墙内(
bind绑定内网 IP) - 防火墙限制来源(只允许应用服务器 IP)
- 不监听公网端口(6379 不对外)
- 不暴露公网:只在内网/防火墙内(
- ③ 禁用危险命令(防滥用)
rename-command FLUSHALL ""(禁用)/KEYS/CONFIG/EVAL等危险命令改名/禁用- 防:误操作(FLUSHALL 清库)、未授权滥用(CONFIG 改配置)
- ACL 也可限制命令(6.0+)
- ④ 数据加密(TLS)
tls-port(TLS 加密传输,6.0+ 支持)- 防窃听(明文协议 Redis 默认不加密)
- ⑤ 系统/运行安全
- 非 root 运行(专用用户)、最小权限(只读 Redis 目录)
- 补丁(及时升级修复漏洞)、日志审计
- ⑥ 其他
- 防暴力破解(密码强度 + 防火墙/fail2ban 限源;Redis 无内置登录失败锁定,可用 6.0+
ACL LOG监控未授权尝试) - 监控未授权访问尝试(日志/告警)
- 内网也是威胁面(内网也有攻击者)——安全是常态不是可选项
- 防暴力破解(密码强度 + 防火墙/fail2ban 限源;Redis 无内置登录失败锁定,可用 6.0+
- ① 认证(身份)
协助记忆
- 安全口诀:“设密码(requirepass/ACL)、不暴露(内网绑定)、禁危险命令(rename)、非 root 运行、TLS 加密”。
- 一句话:“Redis 默认裸奔,设密+隔离+禁危险命令是底线”。
进阶思考
- 为什么 Redis 默认"无认证”(很危险)?
- Redis 设计为"内网可信环境"(高性能、协议简单,默认不强制认证)——但如果暴露公网/内网失陷,无认证=可任意读写(清库/窃数据)。所以生产必须显式设密码 + 隔离。
- ACL(6.0+)比 requirepass 强在哪?
- requirepass:一个全局密码(所有连接同一权限);ACL:多用户 + 细粒度权限(每用户限制可访问的 key/命令)——更精细(如只读用户/指定 key 范围)。安全要求高用 ACL。
- “危险命令"为什么必须禁(具体危害)?
FLUSHALL(清空所有数据)、CONFIG SET(改配置,如关密码/改持久化)、KEYS *(阻塞)、EVAL(Lua 可执行代码)——被未授权/攻击者利用危害大。rename-command禁用/改名可防。
- 为什么 Redis 默认"无认证”(很危险)?
扩展信息
- ACL 命令:
ACL SETUSER/ACL GETUSER/ACL LIST(用户管理)、ACL CAT(命令类别) - 配置安全:
bind(绑定 IP)、protected-mode(保护模式,默认 yes 未认证时限本机)、rename-command - 审计/合规:安全日志(连接/命令审计)、等保对 Redis 等中间件安全要求(认证/访问控制/加密)
- ACL 命令: