半天河
网易游戏高级运维工程师,主要负责云存储的运维;一个既希望跟业务聊又喜欢能够默默在后面忙活的普通运维人。
背景故障现场故障恢复故障恢复分析第一种方式:物理磁盘对拷第二种方式:服务启动时跳过故障扇区来避免异常退出解决方案恢复流程找到故障扇区处的文件移走故障扇区的文件总结
背景
对于 ceph 运维而言,硬件故障导致的 ceph 存储故障是占比最高的一个故障源,小到单个磁盘故障大到机器故障,每天都在上演,ceph 的多副本、故障域等机制已经能够保证绝大部分的硬件故障不影响整个 ceph 集群的可用性,比如:
- 多副本能够确保只要还有一个副本在,数据就不会丢失,业务依然可用
- 故障域的划分能够确保一个故障域内的机器或者机柜故障时,数据不会丢失,业务依然可用
- 有需要时还可以将故障服务踢出集群,触发数据迁移到故障域内其他硬盘,缩短副本数不达标的时间,降低二次故障的影响
但是在日常实际场景中,概率低不代表不会发生,我们必须对这种虽然概率低但是影响可能很大的故障做好预案,确保一旦发生故障能够快速恢复服务。
故障现场
这里先简单介绍一下整个故障现场:
- ceph 的版本是
Hammer 0.94.5
- 故障域是 host,副本数是 2(即同一个业务的数据会写两份,落在不同 host 的各一个硬盘上)
- 一台服务器的一块硬盘故障
- 更换磁盘,同步数据
- 另一台服务器上又有一块硬盘故障
- 数据两个副本存放在这两块硬盘上的所有业务请求被 block 住
- 集群状态关键信息如下:
2 pgs down; 2 pgs peering;
57 requests are blocked > 32 sec;
recovery 4292086/381750087 objects degraded (1.124%);
recovery 7/137511185 unfound (0.000%);
21/967 in osds are down;- down 表示有部分数据的两个副本都不在线
- 有 57 个客户端的请求被 block 超过 32 秒
- 注意这里是 7 个对象的状态是 unfound
故障恢复
故障恢复分析
目前数据层的影响面及恢复分析如下:
- 毫无疑问,第一要务是先拉回所有存储服务
- 服务都在线后才能明确两块硬盘先后故障是否有数据丢失
- 根据数据实际情况再决定后续恢复操作
目前是因为磁盘有坏道,读取坏道数据出错导致服务无法启动。
第一种方式:物理磁盘对拷
最先想到也是操作最简单的一种方法就是将故障盘数据全量拷贝到一块新的硬盘上,忽略其中的故障扇区读取错误,方法如下:
- 在同机房找到一台空闲服务器,插上新硬盘,格式化分区
- 通过 dd+nc 的方式将故障盘数据 dd 到准备的新盘
# 备用机器,新硬盘
nc -lp {port} | dd of=/dev/sde1
# 故障机器
dd if=/dev/sdX conv=noerror | nc -q 10 {backup ip} {nc port} - 拷贝完成后将新盘替换掉故障盘启动服务即可
- 这种方法是可行的,尤其是对于较大范围的磁盘硬件故障这是一个相对稳妥且节省人力的方法
- 但是由于故障 SAS 盘读写速度也就 200MB/s 的峰值,即使保持这个速度,1.2TB 的盘同步完成也需要接近两小时,线上业务坐等两小时是无计可施的保底方法。
第二种方式:服务启动时跳过故障扇区来避免异常退出
解决方案
回过头仔细分析本次故障的信息及规避方法汇总如下:
- 磁盘故障范围小,虽然 dmesg 很多报错信息,但是都集中在同一个扇区
Sep 26 16:09:33 cld-XXXX-XX kernel: [51720946.582063] end_request: critical medium error, dev sdd, sector 49382788
...
Sep 26 16:23:02 cld-XXXX-XX kernel: [51721756.747154] end_request: critical medium error, dev sdd, sector 49382788 - 存储服务启动时的报错信息是读写错误,尝试启动一次上面的 dmesg 信息就会再刷一些通用的日志:
FAILED assert(0 == "Input/output error") - 找到故障扇区所在的文件,移走该文件,移走文件并不会变更该扇区所在的文件,以确保故障扇区依然被占用而不会分配给其他文件使用
- osd 启动时就不会读取故障扇区所在文件,就不会抛异常退出
恢复流程
经过上述分析后,恢复流程就比较清晰而且简单了:
找到故障扇区处的文件
- 在配置文件中调大 osd 服务的
debug_filestore
日志级别到20/20
- 启动故障盘的存储服务,从日志中可以看到故障扇区的文件,如下
7f08ae8ee700 10 filestore(/home/ceph/var/lib/osd/ceph-387) FileStore::read(28.7cb_head/b7e767cb/rb.0.8e1ad1d.238e1f29.00000000a418/head//28) pread error: (5) Input/output error - 得到关键信息:PG 是
28.7cb
,目录结构是b7e767cb
,故障扇区所在文件是rb.0.8e1ad1d.238e1f29.00000000a418
- 根据 filestore 的存储规则定位到该对象在磁盘上的绝对路径如下:
/home/ceph/var/lib/osd/ceph-387/current/28.7cb_head/DIR_B/DIR_C/DIR_7/DIR_6/rb.0.8e1ad1d.238e1f29.00000000a418__head_B7E767CB__1c
TIPS:filestore 是以文件的形式存储,同时为了避免单目录下文件数过多影响性能,osd 会将这些对象分多级目录存储,从前面的日志中可以看到对象路径是<pg_id>/b7e767cb/<object_name>
,这里面的b7e767cb
就是用来分子目录时的目录名,根据当前目录层级是 4(由当前 pool 的总对象数和各层文件数决定),可知道这个 object 存储在磁盘上的路径是:<pg_id>/DIR_B/DIR_C/DIR_7/DIR_6/<object_name>
移走故障扇区的文件
这时候通过 cat 尝试查看这个文件可以看到中途会卡住,dmesg 也会继续刷上面的扇区错误,进一步实锤了磁盘坏道所在文件即为rb.0.8e1ad1d.238e1f29.00000000a418__head_B7E767CB__1c
:
- 移动故障对象
mv /home/ceph/var/lib/osd/ceph-387/current/28.7cb_head/DIR_B/DIR_C/DIR_7/DIR_6/rb.0.8e1ad1d.238e1f29.00000000a418__head_B7E767CB__1c /home/ceph/var/lib/osd/ceph-387 - 拉起服务,成功运行,一段时间后集群状态如下这个 object 状态仍然是 unfound:
1 requests are blocked > 32 sec;
recovery 1/137522689 unfound (0.000%); - 注意这里的
recovery 1/137524092 unfound (0.000%)
,前面服务没有拉起来时 ceph 提示有 7 个对象处于 unfound,现在只剩下一个了,这个对象的 osd 的日志提示如下:
# 从名字上看也恰好是故障扇区的那个文件
28.7cb missing primary copy of b7e767cb/rb.0.8e1ad1d.238e1f29.00000000a418/head//28, unfound
TIPS:ceph 的对象包括三个部分的数据,一个是纯数据部分,一个是文件系统扩展属性提供的元数据,一个 ceph 自己实现的 omap 元数据,这里的 unfound 表示 ceph 在本地没有找到跟元数据中记录的版本一致的对象,unfound 数量变少,说明经过版本比对,其他 6 个对象的版本和其他副本的版本是一致的。
- 这时候只能用以下命令通过 ceph 将这个 pg 下的 object 回滚到另一个副本上的版本了
ceph pg 28.7cb mark_unfound_lost revert
TIPS:因为第一块盘故障离线期间 ceph 是还可以继续使用的,这期间有对象发生数据更新,而更新的这部分数据就只在第二块故障盘上有,因此就造成了这个对象有两个版本,新的版本不可用,因此使用 revert 来告诉 ceph 使用较老版本;如果两个副本同时不可用,只能使用 lost 来标记对象丢失来恢复服务。
至此,集群完全恢复,后续的步骤就是根据这个故障对象名找到 rbd,继而找到所属的虚拟机,请求业务确认影响面并检查虚拟机。
总结
以上就是我们针对双副本对象的两个副本因为故障先后离线这种极端情况下进行数据抢救的过程。针对故障、抢救过程以及后续优化总结如下:
- 单个磁盘故障可能会导致整个机器的 raid 卡控制器 reset
- 在一个副本故障期间,又有新的磁盘硬件故障,就导致了本问描述的严重故障,三副本能大大减少本次故障概率
- 如果硬盘故障,在完全恢复前不要删除数据或者格式化硬盘,以免碰到另一个副本也故障时,连回滚来版本的机会也没有了
- 抢救的根本方法是找到问题症结,如本次故障中采用移走故障文件的方式就可以解决无法启动问题
- ceph 故障都会有比较详细的日志提示,根据提示结合 ceph 的结构特点做针对性的处理即可
- 双副本发生二次故障的概率更高,尤其是使用年限较高深圳过保的老集群
- 对于关掉了 deep-scrub 的集群,需要手动不定期去触发 deep-scrub,防止一些可能隐藏的磁盘故障。
往期精彩
﹀
﹀
﹀
那些年,CDN踩过的坑
智能监控中的时间序列预测
使用 d3.js 绘制资源拓扑图
运维里的人工智能
CI构建环境下的docker build最佳实践