当主重启时 sentinel 没有切换导致数据丢失
说来惭愧,codis 是去年年初就开始调研的。因为想 codis 和 k8s 一起上,重心一直在 k8s 这边。
导致 codis 上线一拖再拖,我们 DBA 用着 twemproxy 那一套老旧的方案快奔溃了。
上个月调研的时候发现 codis 改了 HA 的方案,上了 sentinel。
我们之前在 codis-HA 方案上确实是踩了坑,有一套环境丢了数据。希望 sentinel 能更好一些。但是很快就发现了数据丢失的情况。
复现过程
1 启动一个客户端对 redis 进行写操作,这个客户端全部写完后校验数据有没有缺失
2 强杀 redis,随后立刻重启(sentinel 配置的故障时间内都可以复现)
3 sentinel 检测到重启行为,日志输出 reboot
4 但是数据校验失败
在操作过程中可以明显看到 slave 的 key 在主启动以后减少了几 W 数据
分析
在 sentinelRefreshInstanceInfo 函数中,sentinel 会通过 info 对 master 的 runid 进行检测,当发现 runid 不一致时,输出 reboot 到日志中去
并不进行主从切换,这就导致了主启动时 load 的 RDB 数据较旧,并且会 sync slave 导致 slave 的数据丢失
去 github 看了下 issues,这个问题在 14 年就存在了
Sentinel does not trigger failover in case of master node reboot
emmmm,antirez 的反射弧有点长,最近才关注了这个问题。
他认为 "Only in a very odd condition",导致的这种问题,"For this reason to failover on reboot by default looks a bit too harsh"
他提出的解决方案是
1 添加 PSYNC2 特性,不允许从未知历史记录的复制 ID 进行数据复制,这是防止从数据也丢失了
2 另外或许可以使主一旦重启就进行 failover
从这个解决方案看短期内怕是起码得一个月的功夫。
然后 codis 那里提了 issue 进行合并,redis 从 3.2 到 4.0 估计也得很久(4.0 代码可能有重构)。
所以我的目前解决方案是
取消 k8s 将 codis 进行域名管理的特性,全部使用 ip。重启以后会是一个新的 IP,自然会从主切换成从了。
但是这里会有点小问题
* 以前的主IP需要删除(重启以后k8s会保证IP不重复,但是不能保证下一个启动的容器不使用这个IP) 要删除已经存在sentinel的信息,要对所有sentinel发送SENTINEL RESET 组名,来重置主从情况,
待续
发现 SENTINEL RESET 组名进行删除必须得已经存在新的主,如果 k8s 启动新的容器时执行该指令的时候,新的主没有选举出来,会导致从全部被清除,从而无法切换
所以这一条路走不通。。
新的解决方案是
codis 使用域名进行管理,在 docker 启动容器前执行 SENTINEL failover 组名,来强行切换该组
对于每组 1 主 1 从的架构来说
如果这一组从挂了,会报出 (error) NOGOODSLAVE No suitable slave to promote,不会导致切换
如果主挂了,自然会强行切换,redis 本身的 reboot 不导致切换的特性不会发生
这是一个临时解决方案,毕竟可能会存在多从的场合
这个问题持续更新吧。
未找到相关的 Issues 进行评论
请联系 @tedcy 初始化创建