简介:听到 IO 夯总是让人头疼,那有没有能够剖析 IO 夯问题的利器?
编者按:sysAK(system analyse kit),是龙蜥社区(OpenAnolis)零碎运维 SIG 上面的一个开源我的项目,汇集阿里百万服务器的多年运维教训,针对不同的运维需要提供了一系列工具,造成对立的产品进行服务。作者总结了理论工作中解决的 IO 夯问题的教训,将它梳理成一套实践分析方法并造成 iosdiag 工具,集成到了 sysAK 工具集里。本文将由作者带大家一道领略一下 iosdiag 在 IO 夯畛域叱咤风云的魅力。本文整顿自龙蜥大讲堂第三期技术解读,直播回顾可在龙蜥社区官网查看。
作者:李光水(君然)零碎运维 SIG 核心成员、毛文安(品文)零碎运维 SIG 负责人。
一、引言
这是作者第二次备战双十一,怀着冲动的情绪迎接双十一的到来,未曾想迎来的是一枚深水炸弹:连忙解决一下业务那边呈现的 Load 高问题。
“为什么 Load 高呢?”
“因为有 500 多个过程变成了 D 状态。”
“那为什么会有这个多过程 D 状态呢?”
“因为呈现了 IO 夯问题 …”
曾几何时,听到 IO 夯,作者会有点头皮发麻,为啥呢?因为没有无效伎俩去定位这个问题,或者就算是有伎俩,也得经验山路十八弯,成不成还的看运气,若是侥幸,还能剖析点啥进去,若是不侥幸,把机器整挂掉,得失相当。时至今日,遇到 IO 夯问题再也不虚了,因为作者当初手里有能够剖析 IO 夯问题的利器——sysak iosdiag。
先来看看这个栈,500 多个过程是因为在内核下期待某个磁盘的块设施互斥锁而进入 D 状态,如图 1-1 所示:
图 1-1
互斥锁正被执行读 IO 申请的内核过程 kworker 持有,如图 1-2 所示,只有读 IO 流程实现之后能力开释锁。然而因为 IO 夯住了,读 IO 流程无奈顺利完成,所以就没法失常开释锁了。所以接下来就须要找到是拜访哪块磁盘呈现了 IO 夯?IO 到底夯在哪里?
图 1 -2
之后作者应用 sysak iosdiag 工具找到了呈现 IO 夯问题的磁盘,同时也定位进去这个 IO 是夯在了磁盘侧,如图 1-3 所示:
图 1 -3
作者通过查问 virtio 的后端磁盘的硬件队列的 IO 信息,发现 IO 理论曾经解决完了,进一步查问 vring 信息,发现后端没有更新 used ring,最终将问题起因锁定到了 virtio 后端。最初此问题的具体修复办法咱们在此不再一一表述,总之,该工具能够不便的定界到问题出自前端驱动还是后端设施侧,节俭了不少人力。
通过此问题,作者也简略做了下总结,聊一下 IO 夯的那些事。
二、史诗级的 IO 架构
在聊 IO 夯之前,理解一个 IO 会通过哪些门路还是很有必要的。网上有各式各样的 IO 架构图,足以让人看到眼花撩乱;作者从一个 IO 的生命周期的角度画了一幅图,而后形容一个 IO 在不同阶段的那些事儿(下图中去掉了局部软件档次,如 dm、lvm 等),流程有点长,请急躁看完~
图 2-1
假如咱们以一次用户态程序的写 IO 为例,那么在调用 write 时候会传入一个数据 buf,这个 buf 在内核层面也是有对应 page 的。在默认状况下,IO 会以 buffer io 形式往下走;
假如以 buffer io 形式往下走,走到文件系统层,会将 1 中 buf 外面的数据拷贝到内核 page cache 中,而后把这些 page 置脏,如果此时零碎的脏页水位还没有达到零碎所设置的阈值,这里就返回了,对用户而言这次 IO 完结了;如果此时脏页水位达到零碎所设置的阈值,那么就会启动刷脏流程,这里依据脏页水位具体达到的不同阈值,对用户过程会有不同的解决策略,如短暂休眠或不休眠,在此之后依旧会返回,用户一次 IO 完结;
刷脏是通过 writeback 机制进行,这一流程的触发,可能是通过定期触发,或者如 2 所说水位曾经超过零碎所设定的阈值了,又或者是用户执行了同步命令或者调用了 sync/fsync 之类的 api 等等。writeback 机制将脏页回写包装成一个个 work,而后这些 work 由零碎的 worker 过程,也就是内核的 kworker 过程来执行。刷脏的过程以一个个 inode 为单位,而后将其中的脏页进一步包装成 bio 构造(bio 构造中,会有一个 bio_vec 来形容被包装的脏页 page,简略了解就是会有一个 page 指针指向这个脏页),之后将 bio 提交到 block 层;当然如果此次 IO 波及到文件系统元数据的变更,中途内核过程 jbd 也会往 block 层提交 bio;
bio 进入 block 层之后会经验一系列的限制性的解决,如这个 bio 所包装的数据长度是否过大,有或者是否曾经触发到 IO 限流,因为这些机制有点小简单,就不在图上展现了。在此之后,会尝试与已有的 IO 申请进行合并,具体合并则依据 bio 所形容磁盘上起始扇区和长度与 IO 申请中 bio 形容的磁盘地址是否间断来进行合并。如能合并就不再往下,间接返回了;
如不能合并,则申请一个新的 IO 申请,在多队列架构中,依据磁盘的队列个数和队列深度,在磁盘初始化阶段,在内存上对每条硬件队列曾经事后调配了一个 request 汇合,同时会有对应的 bitmap 来示意每个申请是否曾经被申请。当没有申请能够被申请到时,阐明此队列上的 IO 申请曾经满了,申请的过程将进入深度休眠期待队列上的 IO 申请曾经胜利刷到磁盘并开释 IO 申请,能力申请到;
申请到之后,将 bio 包装成 IO 申请——request,将 IO 申请增加到过程的 plug 队列中,当积蓄到一定量的 IO 申请之后,一把“泄洪”到派发队列上;(补充阐明:plug 队列“蓄流”机制属内核行为,用户无法控制,plug 队列能积攒的 IO 申请数也是有限度的;触发“泄洪”,有可能是 plug 队列满了本人触发的,也有可能是提交完一段数据之后,被动调用的内核接口触发);
request 进入派发队列之后,会被派发到驱动层,上图以 virtio blk 为例,request 会被封装成一个个 sg,这些 sg 外面有形容数据 page 的物理地址、本次 IO 拜访的磁盘起始扇区、数据长度等信息。之后驱动将 sg 推入到 vring 缓存中,vring 缓存在主机上,是主机上 virtio blk 前端和后端磁盘共享的一块可 dma 拜访的内存。sg 推入 vring 之后,会 kick 磁盘提取 IO 并通过 dma 实现数据传输,IO 实现之后,磁盘给主机一个中断,virtio blk 驱动从 vring 中取出实现的 request,进入 io cpmplete 门路;
request 进入 io complete 门路之后,首先执行在 bio 构造体中设置的回调函数,这些回调函数个别在创立 bio 的的流程中指定,其个别负责唤醒期待过程、开释锁资源的操作;之后会记录 io stat 信息,这些信息也是零碎 iostat 工具的指标起源;最初开释掉 request,这个开释并不是将 request 内存清空,而是革除该 reqeust 对应的在硬件队列 request 汇合上的 bitmap 位,以便于起初的 IO 能够再去申请应用;
至此,一个 IO 的生命周期完结,而对于 direct io 的形式,整个过程会短少数据 buf 复制到内核 page cache、脏页回写这个步骤。下面提到的流程可能不是一个实现 IO 生命周期的全副,因为 IO 链路的复杂性,两头也省掉了局部流程,有趣味的读者能够再去摸索摸索,或者退出咱们零碎运维 sig 交换群,欢送一起探讨。
三、臭名远扬的 IO 夯
3.1 何为 IO 夯
IO 夯,可简略了解为 IO 门路在肯定水平上堵住了,轻则通过特定门路的 IO 不可拜访,重则整条 IO 门路堵住不可用,任你多少 IO 丢下来,我就是没反馈。为什么 IO 门路会堵住呢,无外乎是在期待资源。
期待资源个别波及的是 IO 门路上不可重入的临界区,要求过程持有资源进入、开释资源退出,又或者是事物解决型,容许承受无限个过程的事物,但要期待这些过程的事物全副被解决完之后,能力接管新的过程事物,开始解决新一轮的流程。而当处于临界区内的过程,因为内核 bug 或存储介质起因,导致无奈顺利完成 IO 后失常退出,最终造成临界区外的过程因为拿不到资源而处于阻塞状态,导致无 IO 可用。由此可见,只有临界区内的过程不退出这种难堪的状态,整条 IO 门路就不可用。
图 3-1
内核下有条 io complete 的要害门路,这条门路属于可重入门路,其主要职责为对 IO 完结后的收尾工作,个别地,会先执行一个 IO 回调流程,而后更新一些 IO 的 stat 信息,最初完结生命周期。内核中也有一些非凡类的 IO,在 IO 子系统中的解决形式与个别的 IO 有所差别,如 flush/fua io,而作者已经碰到过一起 flush/fua io 夯的问题。flush/fua io 在应用日志型的文件系统场景下可能会比拟常见,如 ext4 文件系统,为了保障文件系统元数据可能真正的长久化存储到磁盘的日志区域,jbd 线程在提交 commit record 的时候会发动这种 IO,而 flush/fua io 的解决流程也是比拟繁琐的:
图 3-2
如上图所示,IO 子系统在解决这个 IO 时,会先发动一个 flush io 到磁盘(在内核中唤作 pre-flush),等这个 IO 完结之后,再发动真正的数据 IO,当磁盘执行完数据 IO 之后,再此发动一个 flush io(在内核中也唤作 post-flush),终于 flush io 完结之后,数据 IO 进入 complete 门路。在这个数据 IO 外面,个别会存在比拟要害的 IO 回调,其波及到开释 buffer head 的 lock bit 或者 page cache 的 lock bit,而且往往期待这个 lock bit 的是 jbd 线程自身;作者已经就遇到 pre-flush io 因为 race 问题被间接开释掉了,导致后续的 IO 流程没有走到,data io 没有失去解决,buffer lock 得不到开释,造成 jbd 夯住,最终引起这个分区的 IO 都得不到响应。
通过本大节的介绍,联合章节 2 的 IO 结构图(图 2-1),能够发现 IO 夯是能够产生 IO 门路上的任何中央。
3.2 IO 夯的危害
从 3.1 可知,IO 夯会造成有 IO 需要的过程无 IO 可用;从业务稳定性角度来看,对于那些有 IO 拜访需要的业务过程,IO 夯可能会引起过程长期阻塞,且在 IO 门路复原之前,都无奈对外提供服务。从零碎稳定性角度来看,IO 夯可能会引起大量的过程进入 D 状态,导致系统高负载,甚至零碎夯住,shell 命令无奈执行,机器无奈登陆,最终不得不重启零碎去解决。
3.3 IO 夯问题分析方法现状
当遇到 IO 夯问题时,咱们通常会剖析 dmesg 中 hungtask 调用栈、或者是 iosta 信息、sysfs/debugfs 中的统计信息,再联合以往教训去揣测问题可能出在哪。当咱们碰到如下图 3-3 所示的 iostat 信息时,依据教训,会狐疑是磁盘侧有 IO 没回,因而狐疑 io 夯在磁盘上,让存储的同学去排查磁盘侧。但这种教训却不肯定靠谱,如果是在磁盘返回到 io complete 之间有内核 bug,iostat 也会呈现下图中的信息。
图 3-3
那如何剖析 IO 夯问题是最无效的呢?答案必定是要找进去夯住的 IO 申请,而后依据申请外面的信息去剖析以后这个申请是处于什么状态、曾经走到哪个门路了。但遗憾的是,目前没有实现这个性能的通用工具,惟一能疾速实现这一需要的,就只有对问题现场做 crash 剖析了,找到夯住的 IO 申请,依据 IO 申请中的信息,再联合代码流程,一步步深刻最终找到问题起因,但前提是业务能够容忍这么操作。
3.4 利器简介——sysak iosdiag
sysAK iosdiag,是 sysAK 工具平台中的 IO 诊断工具,已具备 IO 时延探测、IO 夯诊断两大性能,其中 IO 夯诊断可用于检测以后零碎中 IO 夯事件并确定问题边界。工具的大体架构图 3-4 所示:
图 3-4
首先通过 sysAK 的 iosdiag 性能去使能 IO 夯诊断,这里诊断到 IO 夯之后,会对 IO 进行数据分析,而后造成诊断论断,诊断论断是以 json 的数据格式保留在一个日志文件外面,同时也反对将数据上传到指定的中央,目前反对 oss 的上传形式,不上传的话,数据也会存在机器本地,供调用者去查看。
图 3-5
工具的性能开销状况:单核 cpu 低于 1%、内存耗费低于 10MB、耗费少许磁盘空间保留诊断后果。
工具反对的内核版本品种:3.10/4.9/4.19 多种版本。
iosdiag 诊断后果输入,力求信息精确、后果直观,冀望即使不具备内核 IO 子系统常识的同学也能疾速上手。工具会输入一些结论性的信息,如什么工夫点,检测到了 IO 事件,这是一个什么样的 IO,从哪个 cpu 收回来的,从哪个磁盘的哪个地位拜访多大的数据量,而后这个 IO 夯在哪个门路上,夯住了多久。
图 3-6
四、TODO
工具目前只能笼罩到进入内核 block 层的 IO,在 block 之上的笼罩不到,因而作者目前也在钻研如何扩充工具的覆盖面;其次,工具在后果输入上还不够直观,使用者还无奈简单明了地从输入信息上看到问题,针对这一点,作者也始终在优化。
原文链接
本文为阿里云原创内容,未经容许不得转载。