根本原因是Redis内存溢出导致主库进入只读状态,Sentinel因无法执行INFO等探测命令而误判主节点下线;当used_memory逼近maxmemory且淘汰策略为noeviction时,写命令直接报OOM错误,触发异常切换。
根本原因不是Sentinel本身挂了,而是它依赖的Redis实例在OOM时进入只读或拒绝写入状态,导致Sentinel无法执行INFO、CONFIG GET等探测命令,误判主节点下线。更隐蔽的是:当主库used_memory逼近maxmemory且淘汰策略为noeviction时,写命令直接返回(error) OOM command not allowed when used memory > 'maxmemory',Sentinel发心跳失败后触发误切。
先确认Sentinel进程自身是否健康,再排查它连接的Redis实例:
redis-cli -p 26379 ping —— 看Sentinel是否响应redis-cli -p 26379 sentinel masters —— 查主节点状态字段中flags是否含s_down或o_down
redis-cli info memory | grep -E "used_memory|maxmemory|mem_fragmentation_ratio",若used_memory == maxmemory且mem_fragmentation_ratio > 1.5,Sentinel大概率已失联Sentinel不管理内存,但你可以用外部机制防止它因Redis OOM而误判:
maxmemory-policy allkeys-lru(别用noeviction),避免写入直接失败min-slaves-to-write 1和min-slaves-max-lag 10,让主库在从库延迟过大或掉线时主动拒绝写入,比OOM后被动崩溃更可控redis-cli --bigkeys定期扫描,对识别出的>1MB的hash或zset key 加上EXPIRE,防止单key吃光内存memory.max(Linux cgroup v2),比Redis自身maxmemory更硬性,避免jemalloc分配超限改完配置必须验证Sentinel能否真正感知到主库恢复,而不是卡在“半下线”状态:
redis-cli -p 26379 sentinel failover mymaster,观察日志是否出现+switch-master
redis-cli config set maxmemory 4gb → redis-cli flushdb → 再config set maxmemory 8gb,看Sentinel是否重连并更新is-master-down-by-addr结果redis-cli -p 26379 sentinel sentinels mymaster输出里每个sentinel的last-ping-reply和last-ok-ping-reply时间差,超过down-after-milliseconds值就说明通信仍异常最易被忽略的是:Sentinel默认每10秒发一次INFO,但若主库OOM后响应缓慢,Sentinel可能在超时前就重试三次,累积大量TIME_WAIT连接,最终耗尽文件描述符——所以调大tcp-keepalive和降低down-after-milliseconds要同步做,不能只改一个。