尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Redis 高可用:主从、哨兵、Cluster 三件套,一台机器挂了怎么不停服务?

Redis 高可用:主从、哨兵、Cluster 三件套,一台机器挂了怎么不停服务? Redis 高可用主从、哨兵、Cluster 三件套一台机器挂了怎么不停服务作者鱼宵 实战驱动系列 · 第 4 篇完整课程与可运行源码已开源在 Giteehttps://gitee.com/j67mk2/redis-journey 10 课实战教程本课源码在 lesson-07/一、真实场景单机 Redis 的两个硬伤你搭了个 Redis扛着全站的缓存跑得好好的。直到有一天场景 A服务器宕机了。Redis 里的数据全没了所有请求瞬间压到数据库——数据库跟着挂全站雪崩。场景 B业务起来了数据量超过这台机器的内存。Redis 装不下了你总不能天天加内存条吧这就是单机 Redis 的两个硬伤单点故障挂了就没了和容量上限一台机器装不下。高可用三件套就是来治这两个病的方案解决什么类比主从复制数据备份、读写分离一本作业本复印好几份放不同抽屉哨兵 Sentinel主挂了自动发现、自动换主小区保安盯着大门门坏了自动换锁Cluster数据分片、突破单机容量一个太大的仓库拆成 6 间房分头管演进路线一句话主从复制有备份→ 哨兵自动换主→ Cluster数据分片大容量。下面逐个讲。二、主从复制先保证数据有备份单份数据放一个 Redis 上机器炸了数据就没了。于是搞一主master多从replica主负责写从实时同步主的数据、负责读。好处两个容灾主挂了从还在读写分离读压力分摊到多个从。同步过程是面试常问的讲人话分两步第一次连接全量同步。从节点刚连上主节点彼此没有任何共同记忆——主节点把自己当前所有数据拍一张快照RDB发给从从照着重建一遍。类比新员工入职老板把整本手册复印给他。之后的日常增量同步命令传播。全量同步完成后主每执行一条写命令就把这条命令复读给所有从从跟着执行。类比员工入职后老板每改一条规定都微信同步给大家。配置只要一句从节点上加replicaof 主IP 主端口主节点啥都不用配。一个必须知道的坑复制是异步的——主写完就回客户端 OK不等从复制完。所以极端情况下主刚写完就挂、从还没收到这条命令会丢这条数据主从延迟。这是主从复制的天然短板哨兵也解决不了后面讲。三、哨兵自动盯梢 自动换主主从复制解决了有备份但没解决主挂了谁来宣布新主。总不能主一挂你凌晨爬起来手动登录服务器把从提拔成主吧于是有了哨兵Sentinel。哨兵是一群独立运行的进程一般 3 个奇数个防哨兵自己单点它们的工作分四步监控定时 ping 主节点和从节点看它们活着没。主观下线sdown某个哨兵连续一段时间 ping 不通主——它自己单方面觉得主挂了。但这只是一个保安说大门坏了还不作数。客观下线odown它去问另外几个哨兵你们那边主还活着吗“如果**达到法定人数quorum比如 2 个**的哨兵都说主挂了这才算真的挂了”。选举 故障转移哨兵们投票选出一个领班哨兵由它挑一个数据最新的从节点提拔成新主再让其它从节点改去跟着新主。全程自动。脑裂面试常问讲人话主节点假死比如网络堵了其实它还活着还在写。哨兵们误以为它挂了提拔了一个新主。这时候旧主突然活了还在接收业务写请求——于是变成两个主同时在写数据分叉了。缓解办法之一给主配min-replicas-to-write 1——主必须至少能跟 N 个从同步上才允许写网络一断、主连不上从它就拒绝写避免脑裂期间脏写。四、Cluster数据分片突破单机容量主从哨兵解决了高可用但数据还是全挤在一个主上单机内存到头了就没辙。Cluster 把数据分片。16384 个哈希槽hash slotRedis 不是按哪个 key 放哪台机器分片而是先把整个 keyspace 切成 16384 个槽。每个 key 算一个 CRC16 校验值再对 16384 取模得到它属于几号槽然后把这 16384 个槽分给多个主节点比如 3 个主各分约 5461 个槽。哪个 key 归哪个主看槽落在谁头上。MOVED 重定向你随便连一个节点写 key它一算这个 key 的槽不归我管就回一句MOVED 槽号 正确节点地址让你跳过去。聪明的客户端JedisCluster会记住这张槽→节点路由表以后直接去对的节点不再绕路。为什么偏偏是 16384答案藏在心跳包里这是节点间心跳包大小和槽数量够不够分的权衡。每个节点心跳要捎带自己知道的槽位图16384 位 2KB如果弄成 65536 槽就变 8KB心跳太费带宽。而 16384 已经足够日常把数据分散到几十上百个节点了。哨兵和 Cluster 的区别面试必背维度主从 哨兵Redis Cluster数据分片不分片全在一个主分片到多个主每主管一部分槽容量受单机内存限制可水平扩容客户端连一个地址即可要支持集群协议JedisCluster处理 MOVED故障转移哨兵自动换主节点间自动故障转移适合数据量不大、只要高可用数据量大、要水平扩展五、动手验证亲手 kill 掉主节点看哨兵自动换主完整工程在仓库lesson-07/含 docker-compose.yml 一键起集群。下面是本机真实运行输出全系列最震撼的一段——docker kill redis-master之后哨兵日志完整记录了换主全过程# sdown master mymaster 172.19.0.2 6379 ← 这个哨兵单方面判定主挂了主观下线 # odown master mymaster 172.19.0.2 6379 #quorum 2/2 ← 凑够 2 票客观下线 # try-failover master mymaster 172.19.0.2 6379 ← 开始故障转移 # vote-for-leader 8e88... 1 ← 哨兵间投票选领班 # elected-leader master mymaster ... ← 领班选出 # selected-slave slave 172.19.0.4:6379 ... ← 选中 172.19.0.4 当新主候选 # failover-state-send-slaveof-noone slave 172.19.0.4 ← 让它别再跟从任何人 # promoted-slave slave 172.19.0.4:6379 ← 正式提拔为新主 # failover-state-reconf-slaves master ... ← 让其它从改跟着新主 # switch-master mymaster 172.19.0.2 6379 172.19.0.4 6379 ← 切换完成 # failover-end master mymaster 172.19.0.2 6379 ← 转移结束看懂这条链哨兵机制你就彻底通了单方面觉得挂sdown→ 投票凑够数odown→ 选领班 → 挑新主 → 切换switch-master。跑一遍比背十遍都管用。Cluster 的 MOVED 也实测给你看。keylesson07:greeting算出来是槽 13384归 17002 节点管我们故意连只管 0-5460 槽的 17000 去写它 key lesson07:greeting 落在哪个槽 13384 直接在 17000 上写它 MOVED 13384 127.0.0.1:17002 ← 17000 说这key不归我你去 17002 用 -c 集群模式写自动跳转 OK数据确实分片了——写 9 个 key散落在三个主上槽 3867、7994、12121…各归各的节点。JedisCluster 代码里你完全不用关心 key 在哪个节点它替你算槽、跳转、刷新路由SetHostAndPortseedNodesnewHashSet();// 种子节点给集群一小部分地址即可seedNodes.add(newHostAndPort(127.0.0.1,17000));seedNodes.add(newHostAndPort(127.0.0.1,17001));seedNodes.add(newHostAndPort(127.0.0.1,17002));try(JedisClusterclusternewJedisCluster(seedNodes)){cluster.set(lesson07:greeting,你好Redis Cluster);// 自动算槽、自动路由Stringvcluster.get(lesson07:greeting);// 读回来自动去对的节点intslotJedisClusterCRC16.getSlot(lesson07:greeting);// 直观感受 key→槽}六、挑战题答案都在仓库里跑起来才知道⭐ 在主从拓扑里往主写一个新 key到两个从分别get看能否读到再把一台从停掉观察主info replication里connected_slaves的变化。⭐⭐ 手动再做一次故障转移kill 当前主节点用docker logs redis-sentinel-1找出switch-master那一行确认新主是谁再去新主上info replication看它的从列表。⭐⭐ 在集群里用redis-cli -c -p 17000 set和不带-c各写同一个 key对比一次返回OK、一次返回MOVED——想想为什么JedisCluster 又是怎么帮你免掉这件事的。⭐⭐⭐ 思考题如果集群里某个主节点宕机docker kill redis-node-1Cluster 会怎么自动处理你的 JedisCluster 还能正常读写落在它槽上的 key 吗提示它有从节点。动手 kill 一个主节点观察cluster nodes变化。七、面试回答模板背下来面试官Redis 高可用是怎么做的三层演进主从复制保证数据有备份第一次全量同步 RDB之后增量同步命令传播异步复制有延迟哨兵负责自动换主监控 → 主观下线 → 客观下线凑 quorum → 选举领班 故障转移还有脑裂问题用 min-replicas-to-write 缓解Cluster 做数据分片突破容量16384 个哈希槽CRC16 取模定位MOVED 重定向客户端 JedisCluster 自动路由。选型数据量不大只要高可用用主从哨兵要水平扩容用 Cluster。八、总结层解决什么关键机制面试高频点主从复制数据备份、读写分离全量(RDB)增量(命令传播)异步异步会丢刚写的数据哨兵主挂了自动换主sdown → odown → 选主 → switch-master脑裂怎么缓解Cluster突破单机容量16384 槽 MOVED为什么 16384、哨兵 vs Cluster记住这条单机 Redis 的两个病挂了就没、装不下分别用主从备份和 Cluster分片治哨兵负责中间那个自动换主。九、关于这个系列本文是「Java 后端实战精通营」系列第 4 篇原则实战驱动、由浅到深、面试向每篇文章的结论都可以亲手验证。Redis 实战精通营10 课https://gitee.com/j67mk2/redis-journey本文对应源码位置lesson-07/docker-compose.yml 一键起集群、JedisCluster demo挑战题 2 的答案就在哨兵日志里前 3 篇已发布《分布式锁》《缓存一致性》《事务与 Lua》——这套 Redis 系列从单节点一路走到高可用建议按顺序读后续系列陆续发布Dubbo / JVM / JUC / RocketMQ / MySQL / Elasticsearch下一篇预告《Redis 为什么这么快——IO 多路复用、pipeline 提速 100 倍、bigkey 排查实战》——从高可用回到高性能亲手测出 pipeline 的 108 倍差距。跑完上面任何一步遇到问题把终端输出发评论区一起排查。
返回列表