一、Redis Sentinel基础
- 面试题:Redis Sentinel的核心作用是什么?为什么主从复制场景下必须用到它?
回答要点:核心作用是解决主从复制"无法自动故障转移"的痛点,实现Redis服务的高可用(即服务不中断、数据不丢失)。主从复制的本质是"主节点写数据、从节点复制数据",但一旦主节点宕机(比如服务器断电、网络中断),从节点只能被动等待,需要人工手动修改配置把某个从节点升级为主节点------这个过程少则几分钟、多则十几分钟,期间服务完全无法写入,会直接影响业务。而Sentinel相当于"自动运维员",能实时监控主从节点状态,主节点故障后10秒内完成故障检测、从节点筛选、新主节点切换,全程无需人工干预,业务几乎感受不到中断。
生活类比:就像家里的供水系统------主水管(主节点)负责给全家供水,2根备用水管(从节点)平时只备份主水管的水流(复制数据)。如果主水管突然爆裂,没有Sentinel的话,你得自己找维修师傅、关总阀、手动打开备用水管,期间1-2小时没水用,洗衣机停转、没法做饭;有了Sentinel,相当于装了"智能供水切换系统",主水管爆裂的瞬间,系统立刻检测到水压下降,自动关闭主水管、打开备用水管并把它设为新主供水管,你正在洗碗的水龙头都不会停,完全没感知到故障。
- 面试题:Redis Sentinel由哪两部分组成?各自的职责是什么?请用日常场景类比说明。
回答要点:Redis Sentinel由哨兵节点(Sentinel Node) 和数据节点(Data Node) 两部分组成,二者分工明确、协同工作。
◦ 哨兵节点:是特殊的Redis节点,不存储任何业务数据,核心职责有三个------"监控"(实时检查主从节点是否存活)、"判故障"(判断节点是暂时卡顿还是真宕机)、"调切换"(主节点故障后,选新主、让其他从节点连新主)。
◦ 数据节点:就是普通的Redis节点,分两类------主节点(Master)负责接收所有写请求(比如用户存数据、改数据),并把数据同步给从节点;从节点(Slave)只负责接收读请求(比如用户查数据),同时实时复制主节点的数据,相当于"数据备份机"。
生活类比:类似小区的"物业+住户"体系------哨兵节点是物业维修部(不住人、不存私人物品,只做三件事:每天检查电梯/水管/电路是否正常(监控)、判断电梯是偶尔故障还是彻底坏了(判故障)、电梯坏了立刻调备用电梯上线并贴通知(调切换));数据节点是住户家的"主卧室+次卧室"------主卧室(主节点)是家人主要活动区(存日常用品、做决策),次卧室(从节点)备份主卧室的物品(比如备用床品、衣服),平时也能住人(提供读服务),主卧室漏水时,次卧室就能临时当主活动区。
二、Redis Sentinel核心功能与原理
- 面试题:Redis Sentinel官方定义了四大核心功能,请分别解释每个功能的作用,并各举一个生活例子说明。
回答要点:四大功能分别是监控(Monitoring)、自动故障转移(Automatic Failover)、配置提供者(Configuration Provider)、通知(Notification),缺一不可:
◦ 监控:每个哨兵节点每隔1秒,会向主节点、从节点、其他哨兵节点发送"ping"命令,就像"心跳检测"------如果节点在"down-after-milliseconds"(默认30秒)内没回复,哨兵就暂时标记它"可能有问题"。
生活例子:外卖平台给骑手的"实时打卡"------平台(哨兵)每隔1秒给骑手(节点)发一次"是否在线"的请求,骑手正常接单时会立刻回复"在线";如果骑手手机没电关机,30秒内没回复,平台就会标记"这个骑手可能失联了"。
◦ 自动故障转移:当哨兵确认主节点"彻底宕机"后,会立刻执行三步操作------先从所有从节点里选一个"最合格"的当新主节点,再让其他从节点停止复制旧主、改复制新主,最后把旧主节点标记为"备用"(恢复后改当从节点)。
生活例子:学校的"上课老师备用机制"------主老师(主节点)突然发烧请假,教务处(哨兵)5分钟内完成安排:选平时备课最充分的副老师(合格从节点)当主讲课老师,让其他辅助老师(其他从节点)配合新主老师发课件、改作业,等主老师病好回来,就当辅助老师(从节点)帮忙。
◦ 配置提供者:客户端(比如Java程序)启动时,不知道哪个是主节点、哪个是从节点,这时会先连接哨兵节点,哨兵会直接返回"当前正在工作的主节点地址",客户端再去连主节点写数据。
生活例子:你去陌生城市找连锁奶茶店------你不知道哪家店是"主店"(能点所有新品)、哪家是"分店"(只卖常规款),打开奶茶APP(客户端),APP先连接品牌总部系统(哨兵),总部告诉你"当前营业的主店在XX路123号",你直接导航过去点新品,不用自己查所有门店信息。
◦ 通知:故障转移完成后,哨兵会把"新主节点地址、旧主节点状态、从节点调整情况"等信息,通过短信、邮件或API通知给客户端、运维人员。
生活例子:快递柜的"取件通知"------快递员(哨兵)把快递从旧柜子(旧主节点)转到新柜子(新主节点)后,系统会立刻给你发短信(通知):"您的快递已转移到2号柜,取件码123456",你不用反复去旧柜子查,直接去新柜子取就行。
- 面试题:Redis Sentinel靠三个"定时任务"实现节点监控和拓扑感知,这三个任务分别是什么?各自的周期和作用是什么?
回答要点:三个定时任务是Sentinel的"核心手脚",周期和作用完全不同,共同支撑起监控和故障检测:
◦ 任务1:每隔10秒,每个哨兵向主节点、从节点发送"info"命令。作用是获取最新的"拓扑结构"------比如主节点有多少个从节点、每个从节点的IP/端口、从节点复制主节点的数据进度(偏移量),确保哨兵始终知道"整个集群的成员和状态"。
生活例子:公司部门经理(哨兵)每周一(10秒周期)给部门所有员工(主/从节点)发"工作周报收集表"(info命令),通过表格知道"部门有多少人、谁是新入职的(新从节点)、每个人上周做了多少工作(复制进度)",避免有人离职了经理还不知道。
◦ 任务2:每隔2秒,每个哨兵向"sentinel:hello"频道(Redis的内置频道)发送一条消息,内容包括"自己的IP/端口、对主节点的判断(比如主节点是否正常)、当前哨兵的状态"。作用是让所有哨兵互相感知------你知道我在、我知道你在,同时交换对主节点的看法,避免单个哨兵"孤陋寡闻"。
生活例子:小区业主群(sentinel:hello频道)里,每个业主(哨兵)每隔2分钟发一条"我家水电正常"(自身状态)+"我看楼下超市还开着(对主节点的判断)"的消息,大家通过群消息知道"有多少业主在线、大家对小区设施的看法是否一致",比如有人说"超市关了",其他人看到后会一起确认,避免单个业主误判。
◦ 任务3:每隔1秒,每个哨兵向主节点、从节点、其他哨兵节点发送"ping"命令。作用是做"实时心跳检测"------这是最频繁的任务,确保能最快发现节点宕机,比如主节点突然断网,1秒内哨兵就会收到"ping没回复"的信号,开始后续判断。
生活例子:家长(哨兵)每隔1分钟给独自在家的孩子(节点)发一条"在吗"(ping命令),孩子正常时会立刻回复"在",如果孩子没回复,家长1分钟内就会察觉"可能有问题",赶紧打电话确认,不会等半小时才发现。
- 面试题:什么是Redis Sentinel的"主观下线(SDOWN)"和"客观下线(ODOWN)"?两者的区别是什么?为什么主节点需要"客观下线",从节点不需要?
回答要点:主观下线和客观下线是哨兵判断节点故障的"两步法",避免误判和漏判:
◦ 主观下线(Subjective Down):单个哨兵节点通过"1秒ping任务"发现,某个节点(主或从)超过"down-after-milliseconds"时间没回复,就独自认为"这个节点宕机了"------这是单个哨兵的"个人判断",可能存在误判(比如节点只是网络卡顿,不是真宕机)。
◦ 客观下线(Objective Down):只有当"被主观下线的节点是主节点"时,哨兵才会发起"客观下线判断"------它会向其他哨兵发送"sentinel is-master-down-by-addr"命令,问"你觉得主节点宕机了吗?",如果超过"quorum"(预设的最小同意数,比如3个哨兵里至少2个同意)的哨兵都回复"我也觉得主节点宕机了",这时才会确认"主节点真的宕机了",触发故障转移。
两者的核心区别:主观下线是"个人意见",可能不准;客观下线是"多数共识",更可靠。从节点不需要客观下线,因为从节点故障只影响读服务,主节点故障影响写服务------读服务断了可以用其他从节点补,写服务断了必须100%确认主节点真宕机,才敢切换,避免"主节点只是卡了,哨兵却误把从节点升为主,导致数据不一致"。
生活例子:判断班级同学是否"真的没来上课"------① 主观下线:你进教室看到小明座位空着(单个哨兵ping没回复),就觉得"小明没来"(主观下线),但其实小明只是去厕所了(网络卡顿);② 客观下线:你问了周围5个同学(其他哨兵),有4个(超过quorum=3)说"一整节课都没看到小明"(也主观下线),这时大家一起判断"小明真的没来"(客观下线),才会告诉老师。如果只是判断"小红没在座位上"(从节点),你一个人看到就够了(不用问别人),因为小红不在不影响上课,其他同学还在。
- 面试题:Redis Sentinel如何选举"领导者节点"来负责故障转移?为什么必须选领导者,不能所有哨兵一起处理?
回答要点:Sentinel用"Raft算法"选举领导者,流程分四步,核心是"少数服从多数、避免多头指挥":
-
发起请求:某个哨兵确认主节点"主观下线"后,会向其他所有哨兵发送"sentinel is-master-down-by-addr"命令,同时附带"让我当领导者"的请求------相当于"我觉得主节点坏了,我来负责修,大家同意吗?"。
-
投票同意:其他哨兵收到请求后,如果"还没同意过其他哨兵的请求"(每个哨兵在一次选举中只能投1票),就会回复"同意",否则回复"拒绝"。
-
确认当选:如果发起请求的哨兵收到的"同意票数"超过"max(quorum, 哨兵总数/2 + 1)"(比如3个哨兵,quorum=2,max(2, 3/2+1)=2,超过2票即当选),就会成为领导者;如果没超过,就等下一轮重新发起。
-
执行转移:领导者当选后,独自负责故障转移的所有操作(选新主、调从节点、通知客户端),其他哨兵只负责监控,不插手。
必须选领导者的原因:避免"多头指挥"------如果所有哨兵一起处理故障转移,可能出现"两个哨兵同时选不同的从节点当新主",导致集群出现两个主节点(脑裂),数据彻底混乱。就像一个团队只能有一个队长,大家都指挥的话,没人知道该听谁的。
生活例子:班级选"临时组长"处理教室卫生问题(故障转移)------① 小明发现教室地面脏了(主节点主观下线),举手说"我来当组长安排打扫,大家同意吗?"(发起请求);② 小红和小刚没投过别人,举手同意(投票同意),小明得到2票(3个同学,超过2票),当选组长(确认当选);③ 小明安排小红擦黑板、小刚扫地(执行转移),自己不插手具体工作,避免小红和小刚都安排任务导致混乱。
- 面试题:Sentinel选举领导者时,"max(quorum, 哨兵总数/2 + 1)"这个票数规则怎么理解?举个例子说明为什么需要这个规则。
回答要点:这个规则的核心是"确保领导者得到'足够多'的支持,既符合quorum的预设要求,又满足'超过半数'的多数原则,避免少数哨兵选出来的领导者不被认可"。
◦ "quorum"是哨兵配置文件里预设的"判断主节点客观下线的最小同意数"(比如配置quorum=2),确保至少有quorum个哨兵认为主节点故障,才会触发选举;
◦ "哨兵总数/2 + 1"是"超过半数"的票数(比如3个哨兵需2票,4个需3票),确保领导者得到多数支持,避免"3个哨兵里2个选A,1个选B,A以2票当选,符合多数"。
例子1:3个哨兵,quorum=2。max(2, 3/2+1)=max(2, 2.5)=2,此时只要得到2票(超过2)就可当选。比如哨兵A发起请求,哨兵B和C都同意,A得到2票,满足quorum=2且超过半数,顺利当选;如果A只得到1票,既不满足quorum=2,也没超过半数,无法当选。
例子2:5个哨兵,quorum=3。max(3, 5/2+1)=max(3, 3.5)=3.5,此时需要得到4票(超过3.5)才能当选。如果哨兵A得到3票,虽然满足quorum=3,但没超过3.5,不能当选;得到4票时,既符合quorum要求,又超过半数(5个哨兵的半数是2.5),才能当选,确保后续故障转移时,大多数哨兵认可A的操作,不会出现分歧。
生活例子:公司选项目负责人(领导者),5个部门(哨兵),规定"至少3个部门同意(quorum=3),且同意数超过半数(5/2+1=3.5)"------如果A得到3票,虽然满足3个部门同意,但没超过3.5,其他2个部门可能不认可,后续推动项目会受阻;A得到4票时,4个部门都支持,既够quorum要求,又超过半数,项目推进时没人反对,效率更高。
三、Redis Sentinel新主节点挑选
- 面试题:Redis Sentinel故障转移时,如何从多个从节点中挑选"最合格"的新主节点?挑选流程分几步?每一步的判断标准是什么?
回答要点:挑选新主节点是故障转移的核心,分"四步筛选法",确保选出来的从节点"最健康、数据最完整、最稳定":
第一步:过滤"不健康"的从节点。排除三类从节点:① 处于"主观下线"状态的(比如从节点自己也宕机了);② 5秒内没回复过哨兵ping命令的(比如从节点网络卡顿,没法正常工作);③ 与旧主节点失联时间超过"down-after-milliseconds * 10"的(比如旧主节点down了30秒,从节点失联超过300秒,数据肯定很旧)。这一步先把"明显不能用"的从节点淘汰。
第二步:选"slave-priority(从节点优先级)"最高的。Redis的从节点配置里有"slave-priority"参数(默认100,数值越大优先级越高),优先级最高的从节点直接当选------这是人工预设的"优先顺序",比如把配置更好、性能更强的从节点设为高优先级,确保新主节点性能足够。
第三步:优先级相同,选"复制偏移量"最大的。复制偏移量是从节点复制旧主节点数据的"进度条"------偏移量越大,说明从节点复制的旧主数据越完整(比如旧主节点有1000条数据,偏移量999的从节点比偏移量500的多复制了499条),选它当新主,能最大程度减少数据丢失。
第四步:偏移量也相同,选"runid最小"的。runid是Redis节点启动时生成的唯一ID(类似身份证号),runid越小,说明节点启动时间越早------选启动早的节点,因为它运行更稳定(比如运行了1年的节点比运行1天的节点更不容易出问题)。
生活例子:学校选"临时班长"(新主节点),从5个副班长(从节点)里挑:
第一步:先排除------① 请假没来的(主观下线);② 老师喊了5次都没回应的(没回复ping);③ 一周没来上学的(与旧班长失联太久),剩下3个副班长(小明、小红、小刚)。
第二步:看"老师指定的优先级"------老师之前说"成绩前3名的优先",小明是年级第1(slave-priority=150),小红第2(slave-priority=120),小刚第3(slave-priority=100),小明优先级最高,先选小明;如果小明当天请假被排除,就选小红。
第三步:如果小明和小红都是年级前10(优先级相同,都设为120),看"作业完成度"(复制偏移量)------小明完成了98%的作业,小红完成了90%,选小明;如果两人都完成98%,进入第四步。
第四步:看"入学时间"(runid)------小明是一年级入学的(runid=1001,启动早),小红是三年级转来的(runid=3001),选小明,因为小明更熟悉班级纪律和同学情况,当班长更稳定。
四、Redis集群基础与数据分区
- 面试题:Redis集群相比"主从复制+Sentinel",核心优势是什么?解决了前者的哪些痛点?
回答要点:"主从复制+Sentinel"能解决高可用,但有两个致命痛点:① 单机内存上限------所有数据都存在主节点,主节点内存满了就没法扩容(比如主节点是8G内存,存满后不能再存新数据);② 单机性能瓶颈------所有写请求都压在主节点,主节点CPU/IO满了,写服务就会卡顿。而Redis集群的核心优势是"分布式存储+分布式高可用",同时解决这两个痛点:
◦ 分布式存储:把数据分成16384个"槽(slot)",每个主节点负责一部分槽(比如3个主节点,每个负责5461个槽),数据按"hash(key) mod 16384"分配到对应槽------相当于把"大蛋糕(所有数据)切成16384块,3个主节点各拿一块",每个主节点只存自己负责的槽数据,突破了单机内存上限(3个8G主节点,总内存24G)。
◦ 分布式高可用:每个主节点都有1个或多个从节点,主节点故障后,从节点自动升为主(类似Sentinel),且多个主节点同时提供写服务------比如3个主节点,写请求可以分散到3个节点,每个节点的CPU压力只有原来的1/3,解决了单机性能瓶颈。
生活类比:"主从复制+Sentinel"是"单家大超市"------1个主超市(主节点)存1000种商品,2个分店(从节点)备份这些商品,主超市仓库满了就没法进新货(内存上限),顾客结账只能去主超市(写请求集中),高峰时排队1小时;Redis集群是"连锁超市"------3个主超市各负责一片区域的商品(A超市卖食品、B超市卖日用品、C超市卖家电),总商品量3000种(内存扩容3倍),顾客可以去3个超市分别结账(写请求分散),高峰时排队不超过10分钟,某家超市装修(主节点故障),备用超市(从节点)立刻开门,不影响顾客购物。
- 面试题:分布式存储中常见的"数据分区方案"有三种,分别是"节点取余""一致性哈希""虚拟槽",请对比三者的优缺点,以及Redis集群为什么选"虚拟槽"?
回答要点:三种方案的核心区别是"数据如何映射到节点",优缺点对比清晰:
◦ 方案一:节点取余分区(hash(key) mod N,N是节点数)
优点:实现最简单,不用额外维护映射关系------比如3个节点,直接算key的hash值除以3的余数,余数0去节点1,余数1去节点2,余数2去节点3,开发时几行代码就能实现。
缺点:"节点增减时数据迁移量大"------比如N从3变成4,原来余数0的key(去节点1),现在可能变成余数1(去节点2),80%以上的key都要迁移,迁移期间服务卡顿,甚至因网络中断导致数据丢失。
生活例子:学校按"学号 mod 5"分5个班级,学号1→1班,学号2→2班...学号5→5班。如果新增1个班(N=6),原来学号6 mod5=1→1班,现在mod6=0→6班(要换班);学号10 mod5=0→5班,现在mod6=4→4班(要换班),一半以上的学生要搬桌子换班级,课堂秩序混乱,还可能丢课本(数据丢失)。
◦ 方案二:一致性哈希分区(将节点和key哈希到"虚拟圆环",key顺时针找第一个节点)
优点:节点增减只影响"相邻节点"------比如圆环上有节点A(hash=100)、B(hash=200)、C(hash=300),新增节点D(hash=150)在A和B之间,只有原来去A(hash100-150)的key会改去D,其他key不变,迁移量比节点取余少50%以上。
缺点:"节点分布不均,易出现热点"------如果节点IP/端口的hash值集中在圆环某一段,比如节点A(hash=100)和B(hash=110)离得很近,大部分key的hash值都在100-110之间,全去A节点,导致A压力大(热点),B很空闲;而且节点故障后,所有去该节点的key会全转移到下一个节点,比如A故障,100-200的key全去B,B瞬间压力翻倍(雪崩)。
生活例子:社区的自提柜分布------把自提柜的编号哈希到圆环上,柜A(hash=100)、柜B(hash=200)、柜C(hash=300),住户门牌号哈希后找最近的自提柜,门牌号1-150的去柜A,151-250的去柜B,251-300的去柜C。新增柜D(hash=150)后,只有100-150的住户改去柜D,其他不变(迁移量少);但如果柜A坏了,100-200的住户包裹全堆到柜B,柜B原本放50个包裹,现在要放150个,直接爆满(压力骤增),住户取件要等半小时。
◦ 方案三:虚拟槽分区(Redis集群用此方案)------先把数据映射到16384个"虚拟槽",再把槽分配给节点,key按"hash(key) mod 16384"确定槽,再找槽对应的节点。
优点:① 节点增减只迁移"部分槽"------比如3个节点各负责5461个槽,新增1个节点,只需从每个旧节点迁移1365个槽给新节点,迁移量仅25%(1/4),且迁移时按槽分批进行,不影响其他槽的服务;② 槽分布均匀------人工或自动分配槽,确保每个节点负责的槽数差不多(16384能被2-100个节点整除),避免热点;③ 槽是"数据迁移的最小单位"------迁移时只动槽,不用逐个迁移key,操作简单,且Redis自带槽迁移工具,不用手动写脚本。
缺点:需要维护"槽-节点"的映射关系------每个节点都要知道"哪个槽属于哪个节点",但Redis集群会通过Gossip协议自动同步这个映射,不用人工维护,只有新增/删除节点时才需要手动触发槽分配。
Redis集群选"虚拟槽"的核心原因:兼顾"低迁移量、均匀分布、易维护",完美解决了节点取余的"高迁移量"和一致性哈希的"分布不均"问题,且16384个槽的数量设计合理------既不会因槽太少导致单个槽数据量过大(迁移慢),也不会因槽太多导致节点维护成本高(每个槽占用内存少),最适合Redis的分布式场景。
生活例子:外卖平台按"16384个片区(槽)"分配骑手(节点),3个骑手各负责5461个片区,顾客下单时,按"地址hash mod 16384"确定片区,再找片区对应的骑手。新增1个骑手后,从每个旧骑手手里分1365个片区给新骑手(每次分1个片区,分完1个再分下一个),旧骑手继续送其他片区的订单,顾客下单不受影响;每个骑手负责4096个片区,订单量差不多(不忙不闲),不会出现某个骑手一天送200单、另一个只送50单的情况。
五、Redis集群创建与故障转移
- 面试题:创建一个"完整高可用"的Redis集群,至少需要多少个节点?为什么?部署时主节点为什么不能放在同一台物理机上?
回答要点:至少需要6个节点(3主3从),缺一不可,原因和"故障转移的投票规则"直接相关:
◦ 故障转移的投票要求:主节点故障后,从节点要当选新主,必须得到"超过半数的主节点投票"(比如3个主节点,至少2个投票同意)。如果节点数少于6个(比如2主2从),1个主节点故障后,只剩1个主节点,从节点最多只能得到1票,没超过半数(2主需2票),故障转移失败,集群无法提供写服务;如果是1主1从,主节点故障后,没有其他主节点投票,从节点永远无法当选新主,集群直接瘫痪。
◦ 3主3从的合理性:3个主节点,1个故障后还剩2个,从节点能得到2票(超过半数),故障转移成功;每个主节点配1个从节点,确保主节点故障后有备用,且3个从节点刚好够3个主节点的备份需求,不多不少------如果配2个从节点,会有1个主节点没备用,故障后无法转移;配4个从节点,会有1个从节点闲置,浪费资源,3主3从是性价比最高的组合。
主节点不能放同一台物理机的原因:避免"物理机单点故障"------如果3个主节点都放在1台物理机上,这台机器断电或宕机(比如硬盘损坏、主板故障),3个主节点会同时故障,从节点虽然在其他机器,但没有主节点能投票(全故障了),故障转移无法进行,整个集群彻底瘫痪,业务无法读写。只有把3个主节点分别放在3台物理机上,才能确保"一台物理机故障,只影响1个主节点,其他2个主节点正常工作,投票能正常进行",故障转移顺利完成,业务不受影响。
生活例子:小区的"应急供电系统"------需要3个主配电箱(主节点)+3个备用配电箱(从节点),共6个。如果3个主配电箱装在同一栋楼(同一物理机),这栋楼因线路老化停电,3个主配电箱全坏,备用配电箱要投票选新主,却没有主配电箱能投票(全故障),整个小区没电,居民只能点蜡烛;如果3个主配电箱分别装在3栋楼(3台物理机),1栋楼停电只影响1个主配电箱,另外2个主配电箱正常,备用配电箱能得到2票,顺利切换供电,小区其他2栋楼不停电,居民正常用电。
- 面试题:Redis集群的故障转移和Sentinel的故障转移,核心区别是什么?为什么会有这些区别?
回答要点:两者都是"主节点故障后自动切换",但核心区别在"监控主体、状态维护、适用场景"三个维度,这些区别源于两者的设计目标不同:
首先是监控主体不同:Redis集群的监控是"分布式监控",所有节点互相监控------每个节点每隔1秒向其他所有节点发送"ping"消息,接收节点回复"pong"消息,若超过"cluster-node-timeout"(默认15秒)没收到回复,发送节点就标记接收节点为"主观下线";而Sentinel的监控是"中心化监控",由单独的哨兵节点负责监控------哨兵节点专门发送ping命令监控主从节点,数据节点不参与监控,只负责存储数据。
其次是状态维护主体不同:Redis集群的状态由所有节点共同维护------"槽-节点"映射关系、节点健康状态等信息,通过Gossip协议在所有节点间同步,每个节点都有完整的集群状态;而Sentinel的状态由哨兵节点单独维护------主从节点的地址、健康状态等信息,只存在于哨兵节点中,数据节点不知道其他节点的状态。
最后是适用场景不同:Redis集群适用于"分布式存储场景"------需要多主节点分片存储数据,突破单机内存和性能瓶颈,比如电商平台的用户购物车数据(数据量大,需要分布式存储);而Sentinel适用于"单主多从场景"------数据量不大,只需高可用,不需要分布式存储,比如小型网站的用户会话存储(数据量小,单主节点足够)。
这些区别的核心原因:两者的设计目标不同。Sentinel的目标是"给单主多从架构加自动故障转移",不需要分布式存储,所以用"中心化监控"更简单------专门的哨兵节点干活,数据节点专注存数据,减少节点间的通信开销;Redis集群的目标是"分布式存储+高可用",需要多主节点协同工作,所以用"分布式监控"更可靠------所有节点都参与监控,避免哨兵节点的单点风险(比如所有哨兵节点宕机,Sentinel就失效了,但Redis集群的节点不会全宕机)。
生活例子:Sentinel故障转移像"小区有专门的安保队(哨兵节点)"------安保队有3个保安,每天巡逻监控大门(主节点)和侧门(从节点),大门坏了,保安们一起商量安排侧门当主门,住户(数据节点)不用管监控,只负责住家;Redis集群故障转移像"小区每个住户都是安全员(所有节点)"------住户既自己住家(存数据),又每天敲邻居家门确认安全(节点ping/pong),大门坏了,住户们一起投票选侧门当主门,不用依赖安保队,就算有1个住户不在家(节点故障),其他住户还能正常投票,更抗风险。
六、Redis集群伸缩
- 面试题:Redis集群如何实现"扩容"(加节点)和"缩容"(删节点)?核心原理是什么?操作时需要注意什么,才能不影响业务?
回答要点:Redis集群伸缩的核心原理是"槽和数据的迁移"------扩容时把旧节点的槽移给新节点,缩容时把待删节点的槽移给其他节点,全程"在线操作",不影响业务读写,这也是Redis集群相比其他分布式缓存的优势之一。
先看扩容流程(以"3主3从→4主4从"为例):
-
启动新节点:新增1个主节点和1个从节点,在配置文件中开启"cluster-enabled yes",让节点运行在集群模式,同时设置"cluster-config-file"指定集群配置文件路径(用于存储集群状态)。
-
加入集群:用"cluster meet 新节点IP 新节点端口"命令,在原有集群的任意一个节点上执行,把新主节点和新从节点加入集群------这一步相当于"介绍新成员给大家认识",原有节点会通过Gossip协议把新节点的信息同步给所有其他节点,几分钟后所有节点都知道新节点存在。
-
迁移槽和数据:这是扩容的核心步骤,需要手动触发或用工具自动执行。先确定要迁移的槽:16384个槽分给4个主节点,每个主节点负责4096个槽,所以要从原有3个主节点中各选1365个槽(3×1365=4095,加上新节点自带的1个槽,共4096个)。然后用"cluster setslot 槽号 importing 新主节点ID"命令,让旧节点把指定槽的 data 导出;再用"cluster setslot 槽号 migrating 旧节点ID"命令,让新节点接收这个槽的 data;最后用"cluster getkeysinslot 槽号 100"命令,把槽里的key分批迁移到新节点(每次迁100个key,避免一次性迁移太多导致卡顿)。
-
配置从节点:在新从节点上执行"cluster replicate 新主节点ID"命令,让新从节点复制新主节点的数据,成为新主节点的备用节点------这一步完成后,扩容就结束了,新主节点开始接收自己负责的槽的读写请求。
再看缩容流程(以"4主4从→3主3从"为例):
-
迁移槽和数据:这是缩容的核心,必须先迁槽再删节点。先确定待删主节点负责的4096个槽,把这些槽平均分给其他3个主节点(每个主节点接收1365或1366个槽)。用和扩容类似的命令,先让待删节点把槽导出,再让其他节点接收槽,分批迁移key,直到待删节点的槽数为0(用"cluster slots"命令可查看槽分布)。
-
下线从节点:先在待删从节点的所有邻居节点上执行"cluster forget 待删从节点ID"命令,让集群忘记这个从节点(不再同步它的信息),然后停止从节点的Redis服务------这一步要确保从节点没有数据要同步,避免数据丢失。
-
下线主节点:确认待删主节点的槽已全部迁移(槽数为0),且没有任何key后,在所有邻居节点上执行"cluster forget 待删主节点ID"命令,让集群忘记这个主节点,最后停止主节点的Redis服务------缩容完成,集群恢复3主3从的结构,业务读写不受影响。
操作时的注意事项有三点:
一是迁移槽时要"分批迁移":每次只迁移1个槽或少量key(比如100个),迁移完1个再迁移下一个,避免一次性迁移大量槽或key导致节点CPU/IO过高,影响业务请求的响应时间(比如电商平台高峰时,迁移太快会导致用户下单卡顿)。
二是迁移前要"检查数据一致性":用"cluster getkeysinslot 槽号 数量"命令,查看迁移前后槽里的key数量是否一致,比如迁移前槽100有500个key,迁移后新节点的槽100也应有500个key,确保没有数据丢失(数据丢失会导致业务报错,比如用户购物车数据不见了)。
三是缩容时要"先迁槽再下线":必须先把待删节点的槽全部迁移到其他节点,确保待删节点不再负责任何槽的读写请求后,再停止节点服务------如果先下线节点再迁槽,槽对应的key会无法访问,用户请求会返回"MOVED"错误(业务无法正常使用)。
生活例子:连锁奶茶店的"扩店"和"关店"就像Redis集群的伸缩:
扩容(开新店):先租一个新店(启动新节点),告诉其他3家老店"新店开了,大家认识一下"(加入集群);然后从每家老店分10个片区的客户(迁移1365个槽),每家老店每次转1个片区的客户信息(分批迁移key),转完1个再转下一个,老店继续服务其他片区的客户;最后招一个店员(新从节点)帮新店做奶茶,扩容完成,新店开始接待自己片区的客户。
缩容(关老店):先把老店负责的40个片区客户,分给其他3家店(迁移4096个槽),每次转1个片区的客户信息,确保客户都能找到新的奶茶店;然后让老店的辅助店员(从节点)离职(下线从节点);最后确认老店没有客户了,再关店(下线主节点),缩容完成,客户买奶茶不受影响。