admin管理员组

文章数量:1580479

从一个不寻常的 I/O 卡顿入手,发现苹果 APFS 的一个严重 bug。

近期有用户反馈频繁遇到了一个奇怪的严重卡顿问题,微信刷朋友圈和查看聊天都非常卡,主线程卡在最普通的 access, rename 等常见 I/O 系统调用,并且经常卡上百 ms,而这种场景的底层接口一般都没干什么大量的 I/O 操作。比如 access 接口也就是获取文件是否存在的轻量操作,正常耗时都只有几十 us 而已,远达不到此时的上百 ms 耗时。

一、分析问题

寻找关键堆栈

堆栈上看,只是很常规的视频号卡片列表滑动时,触发了下载图片和查图片本地缓存的逻辑,通过 access 接口同步查本地图片是否存在,有则直接展示,否则从网络下载图片,下载完成时再尝试删除可能已有的旧文件。这完全是一个非常简单的图片缓存和加载逻辑。

通过搜寻卡顿报告,发现子线程都疑似存在大量的并发 I/O 操作,那是否卡顿的主因是和并发 I/O 有关呢?

尝试触发子线程并发 I/O 这个目录的图片,并打日志输出 access 接口的平均耗时,一切正常。走查功能也一切正常,毫无卡顿。

有同学说可能是目录下文件过多才会有 I/O 问题,在对应目录下构造了足够多的文件,再次走查业务功能,还是一切正常。

最终在多次试验和猜测后,构造出了一个高概率复现的场景,在对应目录下写入10万个小图片伪造图片数据,并触发并发 I/O,此时问题终于复现了。这个时候如果触发视频号卡片滑动,朋友圈卡片滑动,就大概率必现严重的滑动掉帧和卡顿了。

构造必现代码

大概知道了必现路径后,我们构造出了一个必现代码,打开 Instruments 的 System Trace 分析,结果如下:

发现 access 等常规 I/O 接口的平均耗时依旧很低只有几十 us,但等待耗时波动很大,可以达到140 ms,也就导致了主线程每次查询图片存在状态时,单次调用耗时超过了140 ms,而滑动过程中大概存在十几次这样的行为,那最终就是每次滑动都要因为这些 I/O wait time 导致滑动耗时数秒之久,甚至个别情况下还会因此滑动卡死触发 watchdog。

资料领取直通车:大厂面试题锦集+视频教程https://docs.qq/doc/DTlhVekRrZUdDUEpy

免费学习网站:C/C++Linux服务器开发/后台架构师https://ke.qq/course/417774?flowToken=1028592

继续分析 Instruments 报告,发现等待的主因如下:will wait for event/lock xxx.

经过前面的研究,我们已经能够构造一个必现 demo 了。大概如下:

  1. 特定目录下写入大约10万个文件
  2. 主线程触发频繁的 access 接口调用,统计平均耗时
  3. 子线程触发对该目录下的文件遍历并频繁的 rename 操作调用,统计平均耗时

如果2和3是同一个目录且当前目录文件数较多时,那么会高概率稳定复现平均 access 和 rename 等 I/O 接口调用 调用耗时过高的

本文标签: 文件系统小窥大IO