十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从线上事故到生产实践:Redis核心原理与高可用架构全解析

从线上事故到生产实践:Redis核心原理与高可用架构全解析 Redis 是什么从我线上一次事故说起。老规矩先聊点实际的。前几年我负责一个电商类的后端服务当时数据库用的是 MySQL日均请求量上来之后最典型的场景就是首页的商品信息、用户购物车、热点活动配置这些数据被反复查询。单条查询也就几毫秒问题是并发一高数据库连接池直接被打满紧接着就是慢查询堆积、CPU 飙高最后整个服务雪崩。那天晚上我一边盯监控一边想一个问题为什么同一份热点数据要每次都去磁盘里翻一遍后来引入 Redis 做缓存层把热点数据提前放内存里问题迎刃而解。Redis全称 Remote Dictionary Server一个开源的内存键值数据库它最核心的价值就是快——因为数据主要存在内存里单线程处理简单命令时读写性能可以达到每秒十万次以上。它是当前后端架构里不可或缺的中间件也是面试必考、生产必用的基础组件。这篇内容我不打算念文档而是从实际使用的角度把 Redis 到底是什么、核心数据类型怎么用、持久化怎么做、高可用架构怎么搭、生产环境有哪些坑一次性讲透。1. Redis 为什么这么快先从一条命令的生命周期看起很多初学者听到Redis 快这个结论就直接背下来了但问到为什么快就支支吾吾。其实这个问题理解透了你后面看性能排查、看调优方案都会轻松很多。1.1 内存存储与高效数据结构快的第一层底座Redis 的所有数据都存在内存里。这一点看起来简单实际上决定了它和传统关系型数据库最本质的区别。MySQL 的 InnoDB 引擎为了性能也设计了 Buffer Pool 内存缓冲但最终数据还是要落到磁盘的 B 树索引文件里。而 Redis 的核心数据操作完全在内存层面完成没有磁盘寻址、没有随机 I/O 的物理开销这就好比一个人直接把东西放在手边和跑到仓库里去翻找速度差别是量级的。除了内存Redis 内部针对不同数据类型设计了对应的底层编码结构。比如 String 类型除了常规的 SDS简单动态字符串还可能用 int 编码来存整数用 embstr 编码来存短字符串Hash 在字段少、值小的时候用 ziplist 紧凑存储字段多了就升级为 hashtable。目的只有一个在节省内存的同时保证操作高效。很多调优文档里讲的ziplist 阈值就是这个层面的东西。1.2 单线程模型与 I/O 多路复用为什么没有锁竞争反而更快Redis 的网络请求处理和核心命令执行是在单线程里完成的。这个设计经常被误解有人觉得单线程是短板实际上它避开了多线程编程里最头疼的锁竞争和线程切换开销。那单线程怎么承受高并发答案是 I/O 多路复用机制。Redis 基于 epollLinux 上这类事件驱动模型用一个线程同时监听成千上万个客户端连接的读写事件。当没有任何事件发生时线程阻塞在系统调用上一旦某个连接有请求进来系统会立即通知 Redis 处理。这就像一个服务生同时照看很多桌客人哪桌有人招呼就过去服务而不是每桌配一个服务生傻等。这里要强调一点Redis 6.0 之后引入了多线程 I/O主要用于网络读写层面的并发处理但命令执行核心依然是单线程。所以你在写 Lua 脚本、使用事务时依然可以基于命令是顺序执行的这个前提来设计不用担心并发交错的问题。1.3 单线程模型下的性能边界与误区理解了单线程模型也就理解了一个常见的性能铁律Redis 的慢操作会阻塞所有后续请求。比如在生产环境里执行 KEYS 命令它会遍历整个键空间数据量大时可能导致 Redis 阻塞数秒期间所有读写都卡住。正确做法是使用 SCAN 命令分批迭代或者干脆在业务层维护一个索引集合。再比如一次写入超大的 value几 MB 甚至几十 MB序列化和内存拷贝都会消耗较长时间一次删除一个包含几百万元素的大集合也可能阻塞主线程。这些都是大 Key问题后面我会专门展开讲。总而言之Redis 快是事实但快是有条件的快不等于你可以乱用。理解它的底层模型是避免线上事故的第一步。2. 五种基础数据类型很多人只会用 String其实亏大了Redis 被称作数据结构服务器是有原因的。它的五种基础类型——String、Hash、List、Set、ZSet——每一种都对应着一类经典业务场景。我用实际案例逐个拆解。2.1 String不只是字符串计数器、分布式锁、限流都要靠它String 是 Redis 里最基础的类型value 最大能存 512 MB。除了缓存 JSON 字符串它最常见的用法是计数器比如商品的浏览量、用户积分、库存数。这里要注意的是 INCR 和 DECR 命令是原子操作。很多人在 Java 里用 RedisTemplate 调用increment()方法时踩过坑。比如热词里提到的那个报错ERR value is not an integer or out of range。这个错什么意思就是当前 key 存的值不是整数类型。常见原因有两个一是同一个 key 之前被 SET 过一个非数字字符串比如set stock abc再执行 INCR 就会报错二是这个 key 已经被 set 成浮点数了比如 1.5INCR 只支持长整型对它执行也会报错。举个真实场景我在项目里用redisTemplate.opsForValue().increment(order:seq, 1)生成订单号结果一开始没注意order:seq这个 key 被业务方手动 SET 成了一个带时间戳的字符串于是线上就飘这个错。排查的时候不要只盯着代码先到 Redis 里执行get order:seq看看存的到底是什么类型再用type order:seq确认类型基本就能定位。此外String 还可以配合 SETNX 实现分布式锁。核心思路SET key value NX EX seconds只有当 key 不存在时才能设置成功利用这个原子操作获得锁释放锁时为保证只能删自己持有的锁需要先用 GET 比对 value再用 DEL 删除整个过程要用 Lua 脚本保证原子性。后面讲并发扣库存的时候我再细说。2.2 Hash操作对象属性的正确姿势Hash 类型相当于一个 key 下挂了多个 field-value 映射非常适合存对象信息。比如用户资料HSET user:1001 name 张三 age 25 city 北京 HGETALL user:1001 HINCRBY user:1001 score 10相比把整个对象序列化成 JSON 塞进 StringHash 的优势是可以单独读写某个字段不需要把整个对象拉出来再序列化、再写回去。比如用户积分变更只需要HINCRBY user:1001 score 10高效又原子。不过 Hash 也有一个容易被忽视的问题字段级过期时间。Redis 的过期机制面向的是整个 keyHash 里的单个 field 不支持 EXPIRE。如果你需要给对象的某个属性设置过期时间比如优惠券的某个状态字段只能拆成独立的 String key或者在应用层自己做过期判断。很多人一开始没意识到这个限制方案设计到一半才发现很耽误事。2.3 List、Set、ZSet消息队列、去重、排行榜的经典玩法List 是简单的字符串列表底层是双向链表结构支持从两端推入和弹出。它曾经被广泛用作轻量级消息队列生产者用LPUSH塞消息消费者用BRPOP阻塞读取消息。BRPOP 是阻塞版本队列为空时会让连接挂起等待避免空轮询。这个方案简单直接适合中小规模、对消息可靠性要求不高的场景。但要注意List 消息队列没有消费确认机制消息被弹出后如果消费者处理失败这条消息就丢了而且没有广播能力。这也是后来 Redis StreamRedis 5.0 引入要解决的问题Stream 支持消费者组、消息确认、Pending 列表功能上更接近专业 MQ。Set 是无序、去重的集合类型适用场景很明确去重。比如统计一个活动的 UV独立访客数用户每次访问就SADD activity:20250101 userId然后SCARD activity:20250101就能得到当天不重复的用户数。Set 还支持交集、并集、差集运算比如计算两个用户的好友共同关注一句SINTER user:1:follow user:2:follow就搞定了比在数据库里写关联查询不知道快多少倍。ZSet 在 Set 的基础上给每个元素加了一个 score 分数按分数排序。最经典的场景就是排行榜。比如积分榜ZADD leaderboard 100 userA要查 Top10 直接ZREVRANGE leaderboard 0 9 WITHSCORES。ZSet 底层是跳表加哈希表插入、删除、查找的时间复杂度都是 O(log n)性能非常好。电商里热销榜新人榜游戏里战力榜全是这个套路。3. 持久化选型RDB 和 AOF 的组合拳怎么打Redis 是内存数据库一旦进程退出或者机器宕机内存里的数据就全部没了。所以持久化不是可选项而是必选项。Redis 提供了 RDB快照和 AOF追加日志两种机制理解它们的原理和取舍是生产环境配置的关键。3.1 RDB 快照全量备份的利器与丢数据的窗口RDB 生成的是某个时间点的全量内存快照默认文件是 dump.rdb。手动执行SAVE会同步阻塞主进程数据量大时千万别在生产用正确方式是BGSAVERedis 会 fork 一个子进程来生成快照主进程继续处理命令。RDB 的触发方式主要有三种手动执行BGSAVE或SAVE配置自动触发比如默认配置save 900 1 # 900 秒内至少有 1 次写操作 save 300 10 # 300 秒内至少有 10 次写操作 save 60 10000 # 60 秒内至少有 10000 次写操作关闭 Redis 时如果配置了 RDB也会触发一次快照RDB 是定期全量快照这意味着两次快照之间的数据可能丢失。比如 15 分钟一次快照刚写完一条重要数据就宕机了这条数据就丢了。所以在追求数据不丢失的场景下RDB 不能单独扛大旗。但它也有不可替代的优点文件体积小、恢复速度快非常适合做冷备和灾备。我习惯每天定时把 dump.rdb 同步到云存储保留近 7 天版本出问题能快速回滚。3.2 AOF 追加日志每一次写操作都记录但要控制文件膨胀AOF 的思路是把每一条写命令SET、LPUSH、HINCRBY 等以 Redis 协议格式追加到日志文件末尾宕机后重放日志就能恢复数据。相比 RDBAOF 丢失数据的窗口小得多这取决于刷盘策略。AOF 有三种刷盘策略通过appendfsync配置策略行为数据安全性性能影响always每条写命令都 fsync 到磁盘最高最多丢一条命令最慢吞吐下降明显everysec每秒 fsync 一次较好最多丢 1 秒数据性能折中生产最常用no交给操作系统决定何时刷盘最差可能丢大量数据最快生产环境我基本都用 everysec兼顾性能和数据安全。你要做严格的金融类对账可能得考虑 always但要提前做好性能压测。AOF 文件会不断增长所以需要BGREWRITEAOF重写机制子进程根据当前内存中的数据集重新生成一条最小命令集合的 AOF 文件把历史冗余命令清掉。Redis 也会根据配置自动触发重写比如auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb意思是 AOF 文件比上次重写时增长了一倍且文件超过 64 MB就自动重写。3.3 混合持久化生产环境的最优解很多团队在 RDB 和 AOF 之间二选一其实 Redis 4.0 开始支持混合持久化这也是我目前线上配置的默认方案。开启方式aof-use-rdb-preamble yes具体效果是BGREWRITEAOF 时子进程先把当前内存快照以 RDB 格式写入 AOF 文件头部再追加后续的增量写命令。这样既利用了 RDB 快速恢复的优势又保留了 AOF 的少量数据丢失窗口。重启恢复时Redis 加载 AOF 文件前半段直接按 RDB 格式载入速度快后半段重放增量命令数据完整。我在多台 4~8 GB 内存的实例上测试过纯 AOF 恢复可能要几十秒混合持久化能把时间压缩到几秒。这个优化效果非常明显强烈建议生产环境开启。另外提醒一个细节RDB 和 AOF 同时开启时Redis 重启优先加载 AOF 文件因为 AOF 的数据完整度更高。如果 AOF 文件损坏启动会失败这时可以用 Redis 自带的修复工具redis-check-aof --fix处理。我自己遇到过一次 AOF 文件因磁盘写坏导致重启失败的情况修复流程不复杂但一定要有备份习惯。4. 高可用架构主从复制、哨兵、集群各自解决什么问题很多人把 Redis 的三种高可用方案混为一谈其实它们的定位完全不同。主从复制是基础哨兵解决故障自动切换集群解决数据量大、单机内存不够的问题。下面按层次拆开讲。4.1 主从复制读写分离的底层机制主从复制是 Redis 高可用的地基。一个主节点Master可以挂多个从节点Replica从节点实时同步主节点的数据。最直接的价值是读写分离主节点负责写从节点负责读把读压力分散到多个节点。同步流程要理解几个关键点。第一次同步时从节点发送 PSYNC 命令主节点执行 BGSAVE 生成 RDB 快照传给从节点同时把期间产生的写命令缓存到复制缓冲区从节点加载完 RDB再继续接收增量命令。之后的同步就是持续的命令传播阶段主节点把写命令实时推给从节点。配置主从也简单。传统方式是在从节点的 redis.conf 里加一行replicaof 192.168.1.10 6379或者在运行时执行REPLICAOF host port。用 Docker 部署主从时注意要把端口映射出来并确保网络互通比如用 docker-compose 定义两个服务从节点的启动命令里带上--replicaof参数。主从复制有一个坑需要提前知道它是异步复制的。主节点执行完写命令就立即返回客户端从节点的同步存在延迟。如果主节点刚写完就宕机而数据还没来得及传给从节点这部分数据就丢了。所以在设计和选型时对于必须保证不丢数据的场景主从复制本身还不够需要配合其他机制。此外默认配置下从节点是只读的直接往从节点写会报错这算一个保护机制。生产环境我一般在主从基础上再做读写分离所有写请求走主节点复杂统计、报表查询走从节点。但要注意如果业务对数据一致性要求极高刚写入就立刻去读可能会因为复制延迟读到旧值。这种场景要么接受短暂不一致要么在代码里强制读主节点。4.2 哨兵Sentinel故障转移是怎么发现和怎么切换的完整链路主从复制解决了读压力但没有解决高可用如果主节点宕机了从节点不会自动上位整个写入能力就断了。哨兵Sentinel就是来盯主节点、做自动故障转移的。哨兵本质上是一个独立运行的 Redis 进程它的作用可以用三句话概括监控、通知、自动故障转移。部署哨兵要至少 3 个实例奇数个这是为了满足 Raft 协议的一致性要求避免脑裂。比如主节点挂了哨兵们要投票决定谁来做新主节点3 个哨兵中超过半数2 个确认故障才会触发切换。主观下线和客观下线这两个概念要搞清楚。单个哨兵发现主节点心跳超时会标记为主观下线多个哨兵互相确认都发现主节点不可达达到 quorum 数量后才会标记为客观下线进而开始选主。选主时会优先选择复制偏移量最大数据最全的从节点同时会考虑从节点的优先级配置。在 Spring Boot 项目里集成哨兵模式配置很简单spring.redis.sentinel.mastermymaster spring.redis.sentinel.nodes192.168.1.10:26379,192.168.1.11:26379,192.168.1.12:26379应用连接的是哨兵地址哨兵会告诉你当前的主节点是谁主节点切换后客户端会自动感知并连接新的主节点。我在部署时踩过一个坑哨兵的配置文件里sentinel monitor mymaster 127.0.0.1 6379 2如果写的是 127.0.0.1哨兵只会监控本机的 Redis用在单机测试没问题但各哨兵节点分布在多台机器上时就无法正确监控网络中的主节点。生产环境一定要写真实 IP 或可解析的主机名。4.3 Redis Cluster数据分片不是简单的多放几台机器当单机内存不够用或者写入并发太高时就需要 Redis Cluster 集群。集群的核心机制是数据分片整个键空间被分成 16384 个哈希槽每个节点负责一部分槽位。执行CLUSTER KEYSLOT key就能算出一个 key 属于哪个槽这个计算是基于 key 的 CRC16 校验值对 16384 取模。举个例子三主三从的集群节点 A 负责 0~5460 槽节点 B 负责 5461~10922 槽节点 C 负责 10923~16383 槽。客户端计算key的哈希槽后如果请求发给了错误的节点该节点会返回一个 MOVED 重定向错误客户端需要重新请求正确的节点。这也是为什么 Jedis、Lettuce 这类客户端会维护一张槽位与节点映射的缓存表。集群模式需要注意几个限制不支持多 key 操作除非这些 key 在同一个槽里。可以在 key 里使用哈希标签{}比如{user:1001}:cart和{user:1001}:orders大括号里的内容参与哈希计算保证两个 key 落到同一个槽。单 key 的 value 不宜太大因为集群的数据迁移单位是槽而大 key 会让迁移变得很重。集群模式下的数据可靠性依赖于副本。每个主节点至少挂一个从节点主节点挂了从节点才能顶上。集群扩容或缩容时数据迁移过程对线上请求是有影响的。Redis 的迁移方式是按槽迁移迁移过程中 key 可能从源节点迁到目标节点客户端可能收到 ASK 重定向需要感知这种临时状态。建议在业务低峰期做集群变更并在迁移前充分评估数据量。使用redis-cli --cluster reshard命令时可以指定迁移槽的数量和目标节点但要计算好每个节点最终的槽位分布避免数据倾斜。用 Docker 搭建 Cluster 测试环境时最简单的做法是docker run时用--cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000参数启动多个实例再通过redis-cli --cluster create命令完成集群初始化。要提醒的是容器重启后 IP 可能会变而 nodes.conf 里记录的是旧的节点信息所以容器建议用固定 IP 或 host 网络模式。5. 生产环境防坑指南那些在文档里查不到的教训前面讲的都是基础架构这一节我重点说说在真实业务里踩过的具体坑。这些东西文档里大多不会写但对线上稳定性影响极大。5.1 未授权访问最危险的安全漏洞Redis 默认只绑定了 127.0.0.1所以本机访问没问题。但不少人在部署时为了方便把 bind 改成 0.0.0.0又没设密码这时 Redis 就像裸奔在公网上。攻击者可以连接后执行CONFIG SET dir /var/spool/cron/写入计划任务反弹 shell或者写入 SSH 公钥实现免密登录这就是经典的Redis 未授权访问漏洞利用链路。解决方案不复杂一是配置文件里bind指定内网 IP不要把服务直接暴露到公网二是设置强密码在 redis.conf 里加requirepass配置三是如果走公网访问务必用防火墙或安全组白名单四是不要用 root 用户运行 Redis 进程尽量用独立低权限用户。还有一个容易被忽略的点很多人只在 redis.conf 里设置了requirepass却忘了主从复制模式下从节点连接主节点也需要认证。如果从节点没配置masterauth主从同步会一直报NOAUTH Authentication required表现为从节点数据永远同步不过去。这个问题排查起来很隐蔽我栽过一次所以记得在主从两边的配置文件里都配好认证信息。5.2 可视化客户端与序列化问题乱码的真相热词里有 redis desktop manager、another redis desktop manager 这些可视化客户端。它们确实方便但你在 Java 项目里用 RedisTemplate 存数据后打开客户端一看可能是一堆类似\xAC\xED\x00\x05t\x00\x04name的二进制乱码这是怎么回事凡是使用过 RedisTemplate 的人大概率都见过这个。原因很直接Spring Data Redis 默认使用 JDK 序列化器RedisTemplate 会把 Java 对象先序列化成二进制字节数组再写入 Redis。所以你在客户端上看到的不是可读字符串而是序列化后的字节流。解决方式是在配置类里显式指定 key 和 value 的序列化方式。生产环境我一般用 StringRedisSerializer 存 key用 Jackson2JsonRedisSerializer 或 GenericJackson2JsonRedisSerializer 存 value这样存进去的是可读的 JSON 字符串排查问题友好很多。注意序列化方式变更可能导致原有 key 无法反序列化所以上线前要考虑是老 key 兼容还是清理重建。如果你只是临时看看数据用 RDM 时选择 Hex 显示也能看出来大概内容但不如从源头解决。5.3 热 Key 与大 Key缓存治理里的两个隐形杀手大 Key 和热 Key 是缓存治理里最常见的两类问题很多团队都是等线上出故障了才回头治理。大 Key 指的是单个 key 的 value 特别大比如一个 List 里有几百万条数据或者一个 String 值有几 MB。大 Key 的危害很具体一是读写大 Key 的耗时明显增加会阻塞 Redis 单线程二是在集群模式下大 Key 所在节点会成为数据倾斜点三是删除大 Key 时如果直接用 DEL主线程卡顿可能会持续数秒。解决方案有对大集合分片存储比如用多个小 key对确实要删除的大 Key用UNLINK命令异步删除或者用 SCAN 分批删除元素。热 Key 是某一瞬间被超高并发访问的 key比如双十一的爆款商品、微博热搜词条。热 Key 会把请求全部打到同一台 Redis 节点上导致单节点 CPU 被打满而其他节点很闲。常见应对方案有给热 key 加随机后缀把访问分散到多个副本做本地缓存比如 Caffeine把一层 Redis 变成两级缓存或者对热 key 增加副本并让读请求负载均衡。我之前处理过一个案例某个活动商品详情接口的 QPS 冲到 20 万Redis 单分片扛不住最后靠本地缓存加 key 的副本扩容撑住了。5.4 并发扣减库存与 DECR 的原子性别再走先查后改很多业务场景需要扣减库存、扣减余额比如下单扣库存、积分扣减。很多初级同学习惯先 GET 再 SET或者先查出来再在 Java 内存里减一然后写回去。这在并发情况下一定会出问题属于典型的竞态条件。正确姿势是直接使用原子命令// 扣减库存返回扣减后的值 Long remain redisTemplate.opsForValue().decrement(stock:1001, 1); if (remain 0) { // 库存不足需要把超卖的补回来 redisTemplate.opsForValue().increment(stock:1001, 1); throw new RuntimeException(库存不足); }但要小心这个写法的 bug如果并发量极高多个线程同时 decrement可能出现多个线程都拿到同一个负数结果然后多个线程都执行 increment 回补导致库存数量被错误恢复。更严谨的做法是用 Lua 脚本保证判断库存并扣减的整体原子性。在 RedisTemplate 里执行 Lua 脚本的代码结构大致如下String luaScript local stock redis.call(GET, KEYS[1]) if tonumber(stock) tonumber(ARGV[1]) then return redis.call(DECRBY, KEYS[1], ARGV[1]) else return -1 end; Long result redisTemplate.execute( new DefaultRedisScript(luaScript, Long.class), Arrays.asList(stock:1001), 1 );Lua 脚本在 Redis 里是原子执行的脚本执行期间不会插入其他命令所以判断和扣减就能作为一个整体完成。这也是分布式锁和复杂原子操作的核心实现方式。热词里提到java 使用 redistemplate 将 redis 的数减一建议直接采用上面这种方式做。对于分布式锁相比早期用 SETNX 加 EXPIRE 两条命令的做法现在推荐直接用一条原子命令SET lock:order:1001 uuid_value NX PX 30000这样加锁和设置过期时间保持在一条命令里避免锁刚加上就宕机导致死锁的问题。释放锁时用前面说的 Lua 脚本判断 value 是否匹配再 DEL。6. 从入门到落地的学习路径与选型建议写到这里Redis 的核心脉络基本清楚了。最后聊点偏软的经验新人应该按什么顺序学习以及什么场景才值得引入 Redis。第一不要一上来就抠源码。先把五种基础类型用熟每个类型找两个真实场景做一遍比如用 ZSet 写一个排行榜 demo用 RedisTemplate 配置序列化并操作 Hash。这个阶段重点是会用。第二理解持久化和主从复制的原理用 docker-compose 搭一套一主两从三哨兵的架构手动 kill 掉主节点观察哨兵怎么切换主从。这个实验做一遍比看十遍文档都管用。第三再去看 Redis Cluster 官方文档理解哈希槽和数据迁移用 redis-cli 自己建一个三主三从集群试试。第四遇到问题了再回头看源码比如排查大 Key 阻塞、分析内存碎片率这时候源码才能真正读进去。关于选型Redis 不是万能的。如果你的数据量很小QPS 也很低直接查数据库完全没问题引入 Redis 反而增加架构复杂度。如果数据要求强一致性Redis 的异步复制和缓存更新策略都要仔细设计。下面是我个人总结的几个适合用 Redis的信号场景特征Redis 的价值热点数据读多写少缓存层显著降低数据库压力需要计数器、排行榜、去重统计数据结构原生支持性能极高分布式环境下需要锁或限流原子命令和 Lua 脚本天然适合需要毫秒级响应内存访问平均延迟在亚毫秒到毫秒级数据库扛不住大并发读前置缓存或读写分离缓解压力反向的不建议用 Redis信号也很明确数据量大且必须全量落盘、需要复杂 SQL 关联查询、需要事务回滚和多表一致性——这些场景关系型数据库更合适。Redis 的事务虽然也有 MULTI 和 EXEC但它没有回滚机制命令队列里某条报错其他命令照样执行和 MySQL 事务完全不是一回事。最后再分享一个小技巧学习时给自己搭一个本地的可视化管理环境个人使用可以选择 Redis Desktop Manager 或 Another Redis Desktop Manager连接上之后能直观看到不同类型的 key 长什么样。配合redis-cli --stat观察实时操作数再配合MONITOR命令观察线上命令执行情况。不过我个人不太建议随便在生产环境用 MONITOR它在高并发下会输出海量命令日志反而拖慢性能。真想排查用SLOWLOG GET 20看慢命令列表更安全它只会把执行时间超过阈值的命令记录到日志里不干扰线上业务。Redis 这个东西用起来不难难的是把它用对、用稳。希望这篇文章能帮你把基础打牢少走一些我走过的弯路。
返回列表