某大厂分布式存储程序猿大半夜收到电话报警,某个存储节点进程和主控节点心跳丢了。
穿着小内裤起来 检查了一番:网络
看到业务恢复、故障报警消除后,开始分析root cause。
进程处于func状态, gdb attach 上去失败, gcore 也失败,根本就没法看到堆栈。
继续检查业务日志:发现故障在磁盘包障后的日志后出现。
检查内核日志:发现有块nvme 盘掉线了,和pcie root 断开了!!!分布式
和厂商及系统部同窗确认了下,出现NVME盘掉线的状况,短时不影响buffer IO ,只影响direct IO。ide
这就奇怪了,由于咱们的数据流都是走page cache,并且落盘的时候用pthread, 即使磁盘坏掉了,也只应该影响这个pthread, 不该该致使整个存储进程上全部其余的线程,持续周期任务日志都打印不出来的状况。工具
究竟是个什么鬼?测试
现有的日志和现场已经没法提供更多线索了,为了分析这个问题,只有想办法复现这个现象了。线程
怎么复现了?既然是坏盘影响IO,那么我就模拟坏盘吧。
搜索了一卷: 参考 磁盘故障模拟, 发现验证机器上没有相关的工具,也没法安装包,之好做罢。怎么办?日志
喝了一杯茶回来,想到既然是坏盘影响IO, 那么就把有IO的地方mock住!code
说干就干,把raft 中和业务中数据流上pwrite/pread的地方都替换成无限sleep, 加个开关,启动后验证了一遍,一切正常,没有复现哪一个问题。进程
后来仔细分析了下,不能一直sleep后,应该用while(1)啊,由于碰到磁盘故障,DIO执行到这里也不会返回,而且不会切换线程。 因而把上面的 sleep换成while。ci
从新编译执行,打开开关测试 ,仍是一切正常啊!
又分析了一遍,既然NVME盘掉线,直接影响的是DIO,那么mock的时候:全部相关的这类操做都应该换成while(1)没法返回,DIO的操做有哪些?
write(O_DIRECT); sync
grep 了一遍,没有O_DIRECT, 只有sync有几个,也换成了while(1), 从新启动,先正常跑了一通,而后把替换sync为 while(1)的开关打开,没过几分钟,就出现了和线上如出一辙的假死现象。
仔细分析了下咱们的业务,原来在每次元数据更新完都会sync下元数据文件。这个操做在bthread里,为了不同时操做这个文件,前面有锁。而这个操做又是在一个bthread里, 它作这个又会去拿磁盘基本的锁,这个锁又和不少业务线程互斥!!!
这样一旦这个sync huang住没法返回,就会致使存储进程假死!
经过上面的分享能够看到,分析和模拟磁盘故障,须要知道它的本质影响而后想办法模拟手影响的地方,这样才能完全定位根因!