资讯动态

Redis核心机制与生产实践:从数据结构到集群排障

发布时间:2026/10/16 13:11:24 来源:尧图企业网站定制
1. 为什么是Redis先弄懂它解决了什么问题作为一个在后端摸爬滚打了十几年的开发者我每次面试候选人都会问一句你们项目里为什么用 Redis不少人能答出“速度快、支持丰富的数据结构”这种标准答案但再深入问一句“它到底快在哪里”或者“哪些场景不该用它”很多人就卡住了。Redis 全称 Remote Dictionary Server远程字典服务。名字里三个关键词Remote、Dictionary、Server。你先记住这三个词后面很多设计都能对上号。它本质上是一个跑在内存里的键值对数据库核心操作是 O(1) 级别的读写。官方给出的 benchmark 通常是单实例 10 万 QPS 以上实际生产环境我优化过的项目里普通 Linux 服务器、千兆网卡、走本地回环接口Redis 6.x 单线程版本跑 GET/SET 混合压力测试稳定在 8 到 12 万 QPS 也很常见。这个量级对于绝大多数互联网业务已经绰绰有余。最适合读这篇文章的人不是已经能把 Redis 源码背下来的大神而是这几类刚接触 Redis 的后端新人想在项目里引入缓存但心里没底的初级工程师以及明明已经在用 Redis 却经常被线上诡异问题折磨的运维和研发。我会把从数据结构到持久化、再到集群和排障的完整链路讲清楚并且多数内容是基于生产环境的真实经验不是照着官方文档翻译。如果你问我Redis 到底解决什么问题我的回答就一个字快。它把频繁访问的数据从磁盘搬到内存用网络服务的方式提供给应用省掉了 SQL 解析、磁盘寻道、事务日志这些瓶颈。但同时你要记住另一句话缓存不是银弹。Redis 能帮你扛流量也能在配置错误时瞬间压垮你的应用甚至丢数据。所以真正要精通的不只是命令而是理解它的每一条机制在什么条件下成立。2. 核心数据结构内存世界里的几种积木2.1 五大数据类型的理解和使用边界Redis 的常用数据结构就是五种String、Hash、List、Set、ZSet。每个都可以用命令直接操作但只有真正理解每种结构适合什么场景才能少走冤枉路。String 是最基础的Value 可以是字符串、整数、浮点数甚至二进制安全的数据。我用它做过分布式锁、计数器、Session 存储、限流滑动窗口的原子自增。要注意的一点是SET 命令如果带上 EX 或 PX 参数会变成原子性的“设值加过期”这比先 SET 再 EXPIRE 更安全。此外String 在 Redis 底层如果值是整数会使用 int 编码省内存且支持自增如果字符串小于某个阈值内部可能用 embstr 编码而不是 raw。这个细节平时感知不到但在批量写入大量短字符串时内存占用差距挺明显。Hash 本质是一个 String 类型的 field 和 value 的映射表。最适合存对象比如用户信息、商品详情。很多人一开始图省事把整个对象 JSON 序列化塞进一个 String后来发现要更新其中一个字段就得读出来反序列化再写回去容易产生并发覆盖和额外网络开销。改成 Hash 后用 HSET 单字段更新操作粒度细内存效率也高。在 Redis 内存编码层面Hash 在元素少且值小的时候会采用压缩列表键值对多了再退化成哈希表自动切换不用你操心。List 则适合当作消息队列或者时间线数据。我用过它在交易系统里存用户的流水记录LPUSH 往左推LRANGE 翻页读。Redis 6.2 之后还引入了 List 的阻塞命令比如 BLMOVE、BLPOP可以当成一个简易的消息队列。但是我要提醒你如果不是极其简单的异步场景别拿 Redis List 替代专业消息中间件。它在消息可靠性上没有消息确认机制也没有消费位点管理消费端挂了消息大概率丢。真要用也建议结合持久化和人为兜底来做。Set 提供无序、不可重复的元素集合还支持交并差运算。最经典的用途是标签系统、共同关注、抽奖去重。SADD 批量加用户标签SINTER 直接算两个用户的共同兴趣一条命令就能出结果如果用关系型数据库做这类运算SQL 写得复杂还不一定快。另外 Set 在 Server 端可以做随机弹出SRANDMEMBER 适合做抽奖时的不放回随机SPOP 是弹出即删除。ZSet 是让我觉得最值回票价的结构。它给每个元素加了一个 score 分值内部按 score 排序底层是跳表加哈希表。可以做排行榜、优先级队列、延迟队列。比如实时排行榜ZADD 累加分数ZREVRANGE 取出 Top N复杂度是 O(log(N)) 级别的。很多实时排名系统的需求用 ZSet 一条命令搞定不需要另建索引表。延迟队列可以用 score 存触发时间戳定期用 ZRANGEBYSCORE 拉取到期任务。2.2 底层编码机制为什么省内存又快Redis 并不是每一种数据结构都“固定用一种底层实现”。它会根据数据量大小和元素尺寸在几种内部编码之间切换。这就是 Redis 节省内存的核武器之一。比如 Hash 的底层在小数据量下用 ziplist压缩列表存储元素个数超过 hash-max-ziplist-entries 或者单个 value 超过 hash-max-ziplist-value 时转换为 hashtable。ziplist 本身是一块连续内存把多个元素紧凑排列省去了指针存储开销还能利用 CPU 缓存局部性所以读写更快。ZSet 同样有 “ziplist skiplist” 两种形态。当元素数量少score 都是整数元素字节数小的时候直接用一个有序压缩列表一旦超过 threshold就切换成跳表加哈希表。跳表是一种多层链表每一层跨度加大查询时从高层向下搜索查找复杂度平均 O(log N)实现上比平衡树简单得多并发修改也更容易。很多喜欢读源码的人问为什么 Redis 不用红黑树答案就是跳表实现简单、性能足够且支持范围查询时更方便。你在配置文件 redis.conf 里能看到一组类似 hash-max-ziplist-entries 的参数。不同版本可能叫 hash-max-listpack-entriesRedis 7.0 之后替换为 listpack。如果追求极致内存可以适当调低阈值让它更快切换成紧凑结构。但别盲目调紧凑结构修改时可能需要重新分配内存数据量大了反而增加 CPU 消耗。生产上我一般会用 redis-cli --bigkeys 扫描线上实例统计每个 key 的类型、大小和编码再针对性调优。2.3 键空间设计与过期策略Redis 所有 key 都存放在一个全局字典中这个字典我们称为键空间。Keys 的命名规范非常影响可维护性。用业务名:对象id:字段 这种带冒号的分段式前缀比如 user:1001:profile。不要用空格、反斜杠也不要无意义的 UUID 直接当 key。好的键名在排障时一眼能定位业务。过期删除也不是发现过期就立即物理删除的。Redis 采用惰性删除加定期删除的组合策略。惰性删除读 key 时才检查是否过期过期就删定期删除后台每 100ms 抽查部分 key如果过期比例超过 25% 就继续采样删除避免大量过期 key 同时霸占内存。这种设计能平衡 CPU 和内存压力。但要注意如果一批 key 设置了同样的过期时间到期那一秒 Redis 可能会忙一阵子CPU 冲高这就引出了缓存雪崩的经典问题。后面我会专门讲应对方案。3. 持久化机制别让一场重启把数据归零3.1 RDB 与 AOF 的取舍Redis 是内存数据库这意味着如果只有内存进程一退出数据就没了。持久化就是把它落地到磁盘的两条路径。RDB 是生成一个二进制时间点快照文件默认名为 dump.rdb通过 fork 子进程把内存数据写入临时文件最后替换旧文件。优点是恢复速度极快单个文件便于备份迁移缺点是快照有一定间隔如果两次快照之间发生宕机这段时间内的写入就丢了。RDB 的自动触发机制由 save 参数控制例如配置 save 900 1 表示 15 分钟内至少有 1 次写操作就自动生成一次快照。AOF 则是“写后日志”Redis 把每一条写命令追加到文件末尾重启时通过回放命令恢复数据。它的数据安全性比 RDB 高因为可以把 appendfsync 配置成 everysec表示每秒刷盘一次最坏只丢一秒数据也可以配置 always 每次写都刷盘但写性能就会跳水。AOF 文件会不断膨胀所以需要 AOF 重写机制把当前内存里的状态重新生成一条条最小命令集合覆盖掉旧文件。Redis 4.0 之后默认支持 AOFRDB 混合持久化重写时直接用 RDB 格式做基线再把增量命令以 AOF 形式追加兼顾恢复速度和数据安全。我自己的观点是如果业务数据允许丢失 5 到 10 分钟的缓存数据而且你注重恢复效率可以只开 RDB。但凡是涉及到订单、积分、交易流水等不能丢的数据建议打开 AOF并且 appendfsync 设成 everysec。always 在 SSD 上我测过写吞吐下降很大除非你有特殊合规需求否则别用。3.2 完整恢复演练与备份策略备份这种事平时没感觉真出事就后悔没演练。我强烈建议你在测试环境模拟一次“杀掉 Redis 主进程清空 dump 文件然后恢复重启”的过程。关键点在于要先保证 redis.conf 里的 dir 目录存在且有写权限否则 RDB 保存会静默失败。很多线上事故就是没有检查磁盘权限Redis 一直无法写盘结果内存崩了以后什么也没恢复到。另一个备份策略是定期把 dump.rdb 或 AOF 文件 scp/rsync 到其他机器或者上传对象存储。注意不要直接备份运行中的正在写的 RDB 文件容易得到半个文件。最稳妥的方式是用 Redis 的 BGSAVE 命令生成一致性快照后再复制该 RDB 文件。如果用了 AOF备份 AOF 文件前最好先执行 BGREWRITEAOF 触发重写减小文件体积也减少脏数据。恢复顺序上Redis 启动时会优先加载 AOF 文件如果开启了 AOF因为 AOF 数据更完整如果 AOF 文件损坏启动会失败可以用 redis-check-aof 工具修复。RDB 损坏则用 redis-check-rdb 尝试修复。我遇到过一种常见问题AOF 文件末尾被截断导致进程起不来检查日志会提示 bad file format。线上可以用 appendonly.aof 末尾强行补一个不完整的换行来抢救但更推荐直接拿上一份完整备份恢复因为修复后的数据完整性无法保证。3.3 持久化配置的坑与性能影响开启持久化后性能并不是没有代价。RDB 做 BGSAVE 时会 fork 子进程fork 需要复制父进程页表如果你 Redis 占用内存很大比如 20GBfork 可能阻塞主进程几十毫秒甚至更久。所以线上监控如果发现 Redis 在定时快照时出现 latency spike要重点看 fork 耗时。解决方案包括控制单个实例内存不要过大或者适当调大 RDB 保存时间间隔降低频率。AOF 的重写也同样会 fork而且重写期间如果有大量写入会占用额外内存和 IO。在写量很大的场景建议把 AOF 重写触发的 auto-aof-rewrite-percentage 调大比如默认 100%文件增长一倍触发重写可以改成 200%降低重写频率代价是 AOF 文件会更大。真相是任何持久化都不能完全消除故障窗口你需要结合业务接受度设计自己的备份链路绝不能把 Redis 当成像 MySQL 那样有 binlog 和事务保障的“强一致数据库”。4. 高性能缓存的核心内存淘汰与缓存三大难题4.1 maxmemory 与淘汰策略选择Redis 的内存不是无限大的当写入量超过 maxmemory 限制时就需要按配置的淘汰策略移除部分 key否则写命令会直接报错。这个机制和 MySQL 的磁盘满了以后拒绝写入有点像但很多新手不知道默认配置下 maxmemory 是 0表示不限制结果内存被打满后触发系统 OOM进程直接被内核杀掉。maxmemory-policy 常见的有 noeviction、allkeys-lru、allkeys-lfu、volatile-lru、volatile-ttl 等。如果只是纯缓存业务读不到也允许那我推荐 allkeys-lruLRU 是最近最少使用可以保证热点数据留在内存。如果希望根据访问频率淘汰Redis 4.0 之后还有 LFU 策略它会统计每个 key 的访问频率冷数据更快被淘汰。用 LFU 有个好处是: 那些偶尔批量扫一次的大查询不会把真正的热点顶出内存因为它对长期频率有记忆。但我实测下来 LFU 的算法实现有几个可调参数不一定在所有业务上都比 LRU 表现好。还要注意active-expire-cycle 进程会在后台不断清理过期 key淘汰策略是在达到 maxmemory 时主动驱逐。如果你设置的是 noeviction那内存满了以后写命令会报 OOM error这个错误在客户端表现为 “OOM command not allowed when used memory ‘maxmemory’”。很多应用因为没捕获这个异常导致缓存写不进去接口直接 500。所以我建议在缓存场景里别用 noeviction除非你明确知道这个 Redis 是当作数据库用的。4.2 缓存穿透、击穿、雪崩的处理套路这三个词面试必问生产上更常见。缓存穿透指的是查询一个根本不存在的数据缓存里没有请求直接打到数据库如果攻击者伪造大量不存在 id数据库压力巨大。解决办法有三层第一层对不存在的数据也缓存一个空值并设置短过期时间比如 5 分钟第二层用布隆过滤器提前过滤明显不存在的 key第三层在数据库查询入口限流。我个人最常用“缓存空值接口层参数校验”简单有效布隆过滤器适合 key 数量规模巨大且更新不频繁的场景否则布隆过滤器本身维护成本高。缓存击穿是指一个热点 key 在过期的瞬间大量请求同时打到数据库。解决思路是“只让一个请求去重建缓存其他请求等待”。实现可以用互斥锁比如 Redis 的 SETNX 拿到锁后查库并写缓存拿不到锁的线程短暂重试。也可以把缓存热 key 的过期时间延长甚至设置永不过期由后台异步更新。后者更优雅但你需要处理刷新逻辑和数据一致性。我在交易系统里就用“逻辑过期”方案value 里塞一个 expire 时间戳字段查询发现快过期时后台任务刷新读操作永远不阻塞。缓存雪崩是大量 key 在同一时间集中过期导致数据库被瞬间流量压垮。最简单的缓解方法设置过期时间时加一个随机偏移比如 base random(0,300) 秒让 key 的过期时间错开。同时保证 Redis 高可用不能单点宕机全挂。如果 Redis 真的挂了还可以用本地进程内缓存做二级降级但那需要额外的代码和一致性设计让系统在缓存故障时还能先撑一阵子。4.3 用 Lua 脚本和 Pipeline 提升批量操作效率Redis 是单线程执行命令所有命令是按顺序排队的。网络开销往往是性能瓶颈而不是 Redis 本身执行慢。所以高频批量操作一定要用 Pipeline把多条命令打包一次发给服务器服务器最后按顺序回包。Pipeline 并不是事务只是减少了 RTT所以中途某些命令失败不会回滚。如果需要原子性的多条操作必须用 Lua 脚本或者 MULTI/EXEC 事务。但 Redis 事务不支持回滚如果某条命令语法正确但在运行时失败它不会影响后面的命令。大多数场景我会直接写 Lua 脚本将“检查-赋值”这种 loop 操作封装成原子的。例如库存扣减需要先 GET 判断库存充足再 DECR这两步如果分开执行在高并发下会出现超卖。用 Lua 脚本来写Redis 在整个脚本执行期间不会处理其他命令保证了原子性。一个容易踩的坑是Lua 脚本在 Redis 7.0 之前不允许使用随机相关命令比如 SPOP 或 TIME因为从节点无法确定重放结果。如果你在集群模式下用了多键操作还会遇到 key 不在同一 slot 报错。所以写 Lua 前先想清楚 key 应遵守 hash tag 规则把相关业务 key 放在同一个哈希槽比如用 “{user:1001}:balance” 和 “{user:1001}:orders”这样集群可以保证它们在同一分片。5. 高可用与集群架构从单机到支撑亿级流量5.1 主从复制最基础的冗余方案单机 Redis 再快也扛不住整机宕机。主从复制是最简单的高可用方案一个主节点一个或多个从节点。从节点通过 SYNC 或 PSYNC 协议从主节点同步数据。第一次全量同步会生成 RDB 快照传给从节点之后基于连接建立复制缓冲区做增量同步。注意全量同步对主节点有 fork 和网络传输压力如果从节点重新连接频繁可能触发多次全量同步把主节点拖垮。主从复制模式下从节点默认只读。这样的部署可以实现读写分离让读请求分流到从节点。但你必须接受一个事实Redis 主从复制是异步的主节点写入成功后立刻返回从节点可能还落后毫秒级。如果主节点宕机从节点可能丢失一点数据。如果业务要求强一致读不能直接走从节点否则会因为复制延迟读到旧数据。这个延迟可以通过 INFO replication 里的 master_repl_offset 与从节点的 slave_repl_offset 差值监控。配置主从关系很简单从节点 redis.conf 里写入 replicaof master_ip master_port 即可。也有用命令 REPLICAOF 现场切换的。生产环境我建议直接写在配置里避免机器重启后从节点丢失主节点关系。主从复制一个常见坑是主节点设置了 requirepass 时从节点必须配置 masterauth 密码否则同步会失败日志报 “MASTER aborted replication with an error: NOAUTH Authentication required”。5.2 Sentinel哨兵自动故障转移有了主从还需要有人能自动切换。Redis Sentinel 是用来管理多个 Redis 节点的进程它本身也是 Redis 服务但专门做监控、通知、自动故障转移和配置提供。通常至少部署 3 个 Sentinel 进程实例分布在不同的机器上。当一个 Sentinel 发现主节点 ping 不通会先主观下线简单说就是它自己觉得对方挂了当多个 Sentinel 都认为主节点不可达就形成客观下线然后进行自动选举从从节点中选出一个提升为新主节点并让其他从节点改成跟随新主。Sentinel 的 quorum 是确认客观下线所需的最少 Sentinel 数量。不建议设成 1因为单点哨兵的误判率高也不建议太苛刻否则网络分区时可能无法达成协议。实际推荐奇数个 Sentinel比如 3 个quorum 设 2。这有点类似 Raft 的多数派逻辑核心是防止脑裂。使用 Sentinel 时客户端应该从 Sentinel 获取当前主节点地址而不是写死 IP。因为故障切换后地址会变。客户端库里有 sentinel 模式例如 Jedis、Lettuce 都支持。我们以前踩过一个坑应用配置里写着旧主节点 IPSentinel 已经切换到新主但客户端还往旧 IP 写数据导致数据全部丢失。后来改用 Sentinel-aware 的客户端配置问题才解决。切换后主节点的 role 会变日志里会有 switch-master 之类的消息运维上要重点监控这个事件。5.3 Redis Cluster 分片原理与扩缩容当你需要的数据量超过单机内存或者单实例写性能不够Redis Cluster 是官方推荐的分布式方案。它会把整个键空间拆成 16384 个哈希槽hash slot每个 key 通过 CRC16(key) % 16384 计算出属于哪个槽。节点间通过 Cluster bus 通信客户端请求某节点时如果 key 不在该节点上会返回 MOVED 错误告知你正确的节点。所以客户端需要缓存槽位映射降低跳转。Cluster 模式下至少要有 3 个主节点每个主节点最好配置一个从节点这样任何一个主节点挂了从节点可以顶上。槽位可以手动分配也可以用 redis-cli --cluster rebalance 自动分配。扩容时把一部分槽迁移到新节点迁移过程采用 slot 级别的迁移但 key 是逐个搬的期间该槽的请求仍在旧节点处理迁移完成会通知。所以集群扩缩容不是完全无感知的需要避开业务高峰。Cluster 有两个限制很多人忽略第一不支持多键操作跨槽因为多个 key 可能落在不同节点无法保证原子性第二数据淘汰策略是基于节点的每个节点有各自的 maxmemory也就是说整个集群容量是各节点内存之和但误差可能因为 key 分布不均而出现。解决方案是设计 key 时多用 hash tag把相关联的字段用花括号包裹成同一个槽来支持多键事务操作。还有一种常见方案如果业务对数据分片规则有强需求不一定要用官方 Cluster也可以自己用 Redis 客户端实现一致性哈希分片比如经典库中的 ShardedJedis。但是自己实现分片不容易做到动态扩缩容和自动故障转移运维复杂度高所以现在新项目我一般直接上官方 Cluster。5.4 客户端连接与连接池细节很多性能问题不是 Redis 慢而是客户端连接管理不善。每次请求都新建连接握手开销和 TCP 三次握手加起来消耗巨大。正确做法是使用连接池设置合理的 minIdle、maxTotal、maxWaitMillis 等参数。Jedis 的 CommonPool 配置我常用的是 maxTotal1000maxIdle200minIdle50maxWaitMillis3000。具体数值要根据并发峰值调整不是越大越好太大了会占用 Redis 端文件描述符太小了会在高峰期线程阻塞。Redis 服务端也有 maxclients 限制默认 10000如果客户端连接太多会被拒绝且 Redis 会打印日志。你可以通过 INFO clients 查看 connected_clients 和 blocked_clients。连接数飘高时不要急着调大 maxclients先在客户端侧排查是不是连接池泄漏。典型症状是线上 connected_clients 只增不减这通常是因为代码里创建 Jedis 对象后没有 close或者用了 try-with-resources 但内部有分支提前 return。这种泄漏一旦发生重启应用只是临时掩盖过段时间又爆。还有一个隐藏坑Redis 6.0 开始默认开启了 io-threads但只是用来处理网络 IO命令执行仍是单线程。调 io-threads 能提升吞吐但多线程间有锁竞争建议根据 CPU 核数逐步尝试不要一开始就调成 16。我见过把 io-threads 调到 16 后吞吐反而下降的情况因为上下文切换开销大于收益。6. 生产环境常见故障与调优笔记6.1 内存暴涨排查清单内存是最容易出问题的部分。我一般按这个思路排查先看 INFO memory 里的 used_memory_human 和 maxmemory再用 redis-cli --bigkeys 扫描大 key再用 redis-cli --monitor 观察一段时间内哪些命令在大量写入。常见原因有几个第一key 过期时间没有设置或者过期策略被设为 noeviction 且内存超限导致过期 key 堆积第二某个 list 或 hash 无限增长比如消息消费失败一直堆积这种大 key 不仅占内存还容易被慢查询拖垮第三Redis 内部碎片率过高用 INFO memory 看 mem_fragmentation_ratio如果大于 1.5 可以尝试重启或者使用 ACTIVE_DEFRAGMENT 参数但 7.0 之后一般能自动整理。大 key 是万恶之源写大 key 会造成网络拥塞、阻塞主线程、影响持久化 fork 内存。我的经验是单个 key 的 value 超过几百 KB 就要警惕超过 1 MB 要立即优化。比如用户关注列表这种聚合数据可以用 Hash 拆成多字段存而不要让一个 List 里塞几十万条 ID。6.2 慢查询分析与MONITOR的使用边界Redis 慢查询日志记录执行时间超过阈值的命令通过 slowlog-log-slower-than 配置单位是微秒。我通常设置为 1000010ms。线上出现接口延迟第一步就去看 SLOWLOG GET 10它会返回 keys 参数、耗时、时间戳。解析时关注是不是出现 RedisObject 频繁 realloc或者 ops 类型是否为大 key 的集合操作。除了 slowlog很多人喜欢开 MONITOR 抓命令我也用但必须提醒MONITOR 命令会把所有请求实时输出到客户端在高吞吐场景下会把 Redis 主线程拖慢严重时会让 Redis 卡到无法处理正常请求。所以线上最高峰千万别开着 MONITOR 长期跑。想捕捉异常请求短时间抓几十秒关闭。更安全的方式是启用 Redis 内建的 latency monitorCONFIG SET latency-monitor-threshold 100然后 LATENCY LATEST、LATENCY HISTORY 查看各事件的延迟。6.3 键空间通知与事件回调如果业务需要监听 key 过期、删除、更新等事件Redis 2.8 之后可以开启 keyspace notifications。配置 notify-keyspace-events 参数例如 Ex 表示监听 key 过期事件A 表示所有事件。基于这个能力可以做定时任务延迟触发、订单超时提醒。实现原理很简单Redis 在事件发生时向订阅者发送消息客户端用 PSubscribe 订阅特定的频道。生产环境我用它做过“用户下单 30 分钟未支付自动关闭”的功能把订单 id 作为 key 设置过期时间过期事件触发后异步回调业务系统。但这个方案不是完美的。第一过期事件存在时间偏差可能晚几秒才推送对严格时限要求不友好第二如果 Redis 发生主从切换事件通知可能丢失第三SUBSCRIBE 长时间不消费会堆积客户端输出缓冲可能拖垮 Redis。所以在做核心支付类流程时我建议还是用定时轮询或者消息队列的延迟队列来做兜底事件通知只当辅助触发器。6.4 安全基线密码、命名空间与危险命令虽然很多 Redis 部署在内网但安全配置绝不能省。第一设置 requirepass不要留空密码第二设置 bind 参数只监听内网 IP不用 0.0.0.0第三把危险指令比如 FLUSHALL、KEYS、EVAL 在生产环境 rename 成不可调用的名字或者干脆用命令黑名单禁止。Redis 的 CONFIG SET 命令也存在风险若攻击者拿到客户端权限可以直接改配置。有一个容易被忽视的工程问题KV 隔离。多业务共用一个 Redis 集群时即使 key 带前缀区分一旦某个业务逻辑写死清库命令或者批量删除 key很可能误伤其他业务。比较规范的做法是按业务拆不同实例或不同逻辑库Redis 默认 16 个库至少让核心业务和非核心业务物理隔离。Redis Cluster 本身只支持 db 0所以如果你用 Cluster这种隔离只能靠部署多个集群。6.5 从单机迁移到集群的一次实践复盘我之前做过一个项目上线初期单机 Redis 完全够用后来业务量上去内存很快逼近 16GB。为了平滑迁移到 Cluster我们做了这些事先在测试环境开启 Cluster 模式把原 dump 文件导入验证所有 key 的哈希分布然后给应用代码统一封装缓存访问层之前直接散落的 Jedis 调用全部收口方便切换配置。迁移过程中最容易出问题的是事务和 Lua 脚本。我们当时有几个业务用到了 JSON 序列化后存 String然后对整个 key 做更新这不跨 key 没问题。但有一个同步订单的功能用了 MULTI 同时操作两个 key在 Cluster 下直接报 CROSSSLOT 错误。后来我们把那两个 key 设计成相同的 hash tag 前缀问题才解决。另一个坑是 scan 命令虽然支持游标遍历但在 Cluster 下需要按每个节点分别 scan否则只能拿到一个节点的数据。迁移结束后我们跑了数据一致性校验用脚本同时从旧实例和新集群读取部分 key 对比值确认没有丢失才正式切流量。整个过程花了 3 天核心教训是应用代码的缓存访问层一定要封装好否则迁移的时候到处改引用会改到崩溃。7. 我的调优心得和几个实用小脚本最后把我的几个实践经验打包告诉你。排查内存波动我经常用这个组合命令看节点视角的信息redis-cli -h 127.0.0.1 -p 6379 INFO memory redis-cli -h 127.0.0.1 -p 6379 --bigkeys如果想快速扫描 key 数量别用 KEYS阻塞主线程。用 SCAN 游标迭代安全很多。在增强型 shell 里还可以用 redis-cli --scan --pattern user: | head -n 100 做测试但生产环境还是建议改成游标方式。检查最大延迟可以写个简单脚本秒等看一下for i in $(seq 1 20); do redis-cli --latency -h 127.0.0.1 -p 6379 done--latency会输出采样周期内的最小、最大、平均延迟。如果最大延迟经常超过 50ms说明实例可能在做 BGSAVE 或者 AOF 重写也可能是网络抖动。再用 LATENCYDOCTOR 命令Redis 会给你人类可读的调优建议。到这儿Redis 的核心机制和排障思路都过了一遍。我个人实际体会是真正折磨人的不是 Redis 本身而是使用姿势。数据结构选对集群规划合理故障排查有套路这三点能做到线上 Redis 的稳定性就赢了一大半。如果后续你想深挖某个点比如 LFU 调参、集群迁移脚本、Lua 脚本规范随时可以继续往下聊。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑