
Ceph故障分享长文:关于Ceph的一次无硝烟的战争
01前言
本文主要描述的是在一次意外中,我们的Proxmox/Ceph集群上丢失了36个磁盘中的33个,这对我们而言,完全是一场灾难!
下文将会相信描述该事件,同时也包含了如何修复以及回溯该严重故障。
到2020年底,我们终于有了一个长期未完成的维护窗口,以便为客户进行系统升级。在此维护窗口期间(涉及服务器系统的重新启动),涉及的Ceph群集意外进入关机状态。本来计划在晚上早些时候做几个小时的检查清单工作,结果却成了一个紧急情况;让我们称之为噩梦吧(不仅仅是因为它让我们多熬了几个通宵)。因为我们从RCA(故障回溯)中学到了一些东西,所以值得与其他人分享。
但首先,让我们退一步,搞清楚我们这次事件的来龙去脉。
02系统升级
升级的一部分包括3台Debian服务器(我们在这里称它们为server1、server2和server3),它们运行在ProxMoxV5+Debian/stretch上,每个都有12个Ceph OSD(总共65.45TB),这就是Proxmox与Ceph的超融合集群。
首先,我们将ProxMoxV5/stretch系统升级为ProxMoxV6/buster,然后再更新CephV12.13至最新版本14.2版本,由ProxMoxV6/buster支持。Proxmox升级包括将corosync从v2更新到v3。
作为此次升级的一部分,我们必须应用一些配置更改,如调整ring0+ring1地址设置,并将mon_host配置添加到Ceph配置中。
在前两台服务器重新启动期间,我们注意到配置问题。在修复这些问题之后,我们也重新启动了第三台服务器。然后,我们注意到几个Ceph OSD意外停机。升级后NTP服务未按预期工作。根本问题是ntp与systemd timesyncd的竞争条件(请参见#889290)。
因此,Ceph出现了时钟偏移问题,这表明Ceph监视器的时钟不同步(这对于正确的Ceph操作至关重要)。我们最初假设Ceph OSD故障源于这个时钟偏移问题,所以我们处理了它。
在又一轮重新启动之后,为了确保系统以完全相同和正常的配置和服务运行,我们注意到许多失败的OSD。这一次,除了三个OSD(19、21和22)外,其他所有OSD都停机:
我们顿时感到不妙!我们的集群是不是挂了?发生了什么,我们怎么才能把其他的OSD都找回来?我们在日志中偶然发现了这一详细信息:
其他出现故障的OSD也存在同样的问题。我们希望数据本身仍然存在,只有XFS分区的挂载失败了。该Ceph群集最初于2017年安装的Ceph jewel 10.2版本。主要是用于文件存储的。
但是,后来,我们将磁盘从filestore迁移到了bluestore(使用ceph-disk,而不是现在使用的ceph-volume)。ceph-disk引入了包含OSD基本元数据的100MB XFS分区。考虑到我们还有三个可用的OSD,我们决定研究如何重建失败的OSD。ceph社区的一些朋友向我们分享了XFS分区如何工作的(thanks T1, ormandj + peetaur!)。
在创建备份(通过dd)之后,我们尝试在server1上重新创建这样一个XFS分区。我们注意到,即使安装新创建的XFS分区也失败了:
这看起来与我们看到的实际问题非常相关。所以我们尝试执行mkfs。xfs有一系列不同的sunit/swidth配置。使用'-d sunit=512-d swidth=512'至少在当时是有效的,所以我们决定在创建OSD XFS分区时强制使用它。这为我们带来了一个工作的XFS分区。
请注意,sunit不得大于swidth(稍后将详细介绍!)。然后我们重建了如何恢复OSD的所有元数据(activate.monmap、active、block_uuid、bluefs、ceph_fsid、fsid、keyring、kv_backend、magic、mkfs_done、ready、require_OSD_release、systemd、type、whoami)。为了识别UUID,我们可以从“ceph--format json osd dump”读取数据,就像我们所有osd的数据一样:
可以通过以下方式为每个OSD UUID识别相应的原始设备:
可以通过以下方式查询 OSD 的key ID:
现在我们还需要确定底层块设备:
通过所有这些,我们重建了keyring、fsid、whoami、block+block_uid文件。XFS元数据分区中的所有其他文件在每个OSD上都是相同的。
因此,为了Ceph的使用,在XFS分区上放置并调整了相应的元数据之后,我们得到了一个可以工作的OSD!因为我们还需要修复另外32个OSD,所以我们决定自动化这个XFS分区和元数据恢复过程。
我们在/srv/backup上有一个网络共享,用于存储现有分区数据的备份。在每台服务器上,我们都使用一个OSD测试该过程,然后再遍历剩余的失败OSD列表。
我们从server1上的shell脚本开始,然后调整了server2和server3的脚本。这是我们在第三台服务器上执行的脚本。
多亏了这一点,我们成功地使Ceph集群重新启动并运行起来。不过,我们不想在晚上继续Ceph升级,因为我们想知道到底发生了什么,以及系统为什么会这样。RCA(故障回溯)的时间到了!
03根本原因分析
因此,server2上除了三个OSD之外,其他所有OSD都出现了故障,问题似乎与XFS有关。
因此,我们进行RCA(故障回溯)的出发点是,确定server2与server1+server3的不同之处。我最初的假设是,这与相关控制器的一些固件问题有关(后来证明,我是对的!)。
这些磁盘作为JBOD设备连接到ServeRAID M5210控制器(条带大小为512)。固件状态:
这看起来非常有希望,因为server2确实在控制器上使用不同的固件版本运行。但怎么会这样呢?
好的,server2的主板在2020年1月被一名联想/IBM技术人员更换,因为在内存升级过程中,我们的内存插槽出现了故障。作为本程序的一部分,联想/IBM技术人员安装了最新的固件版本。根据我们的文档,一些OSD在2020年3月和4月重建(由于filestore->bluestore迁移)。
事实证明,正是这些OSD在升级中幸存了下来。因此,幸存的驱动器是使用在相关控制器上运行的不同固件版本创建的。所有其他OSD都是使用较旧的控制器固件创建的。但这又有什么区别呢?
现在,让我们检查固件更改日志。24.21.0-0097我们发现:
我们的XFS问题当然与控制器的固件有关。我们还记得,我们的监控系统报告了3月和4月重建的OSD的不同sunit设置。例如,OSD 21被重新创建并获得不同的sunit设置:
我们将新OSD 21与现有OSD(server3上的OSD 25)进行了比较:
由于我们的文档,我们可以比较它们创建的执行日志:
那时候,我们甚至试图追查到这一点,但还没有弄明白。但现在这听起来很像与我们看到的Ceph/XFS故障相关。
我们遵循Occam的razor,假设最简单的解释通常是正确的,那么让我们检查磁盘属性,看看有什么不同:
请参阅server1和server2之间相同磁盘的区别?getiomin选项现在为他们报告了一些不同的内容:
最小I/O大小(iomin,又名BLKIOMIN)大于最佳I/O大小(ioopt,又名BLKIOOPT)是没有意义的。这导致我们遇到了Bug 202127–无法在597T设备上安装或创建xfs,这与我们的发现相匹配。但是为什么这个XFS分区在过去可以工作,而在新的内核版本中却失败了呢?
04XFS的行为改变
现在,我们已经有了所有XFS分区的备份,我们想要追踪,a)何时引入了这种XFS行为,b)是否可以重用XFS分区,如果可以,如何重用XFS分区,而不必从头开始重建(例如,如果您没有可用的Ceph OSD或备份)。
让我们看一下Grml live系统中失败的XFS分区:
无论我们尝试哪种挂载选项,它都会失败:
此外,xfs_repair也没有帮助:
通过“SB stripe unit sanity check failed”(SB条带单元健全性检查失败)消息,我们可以轻松跟踪到以下提交fa4ca9c:
此更改包含在内核版本4.18-rc1及更新版本中:
现在,让我们使用旧的Grml 2017.05版本,尝试使用旧的内核版本(4.9.0):
现在,如果我们使用旧的内核使用新的和正确的sunit/swidth设置挂载文件系统,它应该在磁盘上重写它们:
事实上,挂载这个rewritten的文件系统也适用于较新的内核:
FTR:xfs mount选项中的'sunit=512,swidth=512'与xfs_info的输出'sunit=64,swidth=64'相同(因为mount.xfs的sunit值是以512字节块单位给出的,请参见man 5 xfs,这里报告的xfs_info输出是以块大小(bsize)为4096的块为单位的,所以'sunit=512512:=644096')。
mkfs为 stripe unit and stripe width使用最小和最佳大小;您可以通过以下方式进行检查(请注意,固件版本中,server2报告正确的值,而控制器固件损坏的server3报告无意义):
这就是最初创建的XFS分区使用不正确的sunit/swidth设置创建的根本原因。server1和server3的固件损坏是错误的原因——在旧的xfs/内核版本中忽略了它们,但新版本却直接报错。
请务必阅读XFS常见问题解答“如何计算正确的sunit、swidth值以获得最佳性能”。在RedHat的知识库中,我们还偶然发现了两个有趣的文章:5075561+215001(需要订阅)和#1835947。
05我受到影响了吗?如何解决这个问题?
要检查XFS挂载是否受此问题的影响,请使用以下命令行:
如果您遇到上述情况,使原始XFS分区重新工作的唯一已知解决方案是重新引导到较旧的内核版本(4.17或更旧),使用正确的sunit/swidth设置挂载XFS分区,然后重新引导到新系统(内核版本)。
06经验教训
- 记录所有内容并确保所有相关信息可用(包括实际更改时间、使用的内核/软件包/固件/…版本)。完整的文档是我们在本案例中最重要的资产,因为我们有紧急处理期间以及RCA(故障回溯)期间所需的所有数据和信息
- 如果发生意外故障,请深入挖掘故障原因
- 知道该问谁,一个专家级的技术支持能够少走很多弯路
- 在shell中包含时间戳使重建更容易(涉及的人员和文档越多,就越难完成重建)
- 密切关注变更日志/发行说明
- 应用定期更新,不要忘记不可见层(例如BIOS、控制器/磁盘固件、IPMI/OOB(ILO/RAC/IMM/…)固件)
- 应用定期重新启动,以避免可能的增量问题(这也会使调试更加困难)
原文: https://michael-prokop.at/blog/2021/04/09/a-ceph-war-story/
文章转载自公众号:新钛云服
