引子

性能问题有时候不像稳定性问题那样,出了bug, ok, fix该bug,搞定它就行了。性能问题如果涉及到文件系统自身架构方面缺陷的话,是很难解的。

不过通过解这些性能问题,使我慢慢地熟悉了文件系统工作原理和架构设计,慢慢地会发现之前看不懂的内核ext4/f2fs社区那些技术邮件交流,自己现在能全部看懂了,而且还可以跟大牛搞技术合作了。

问题爆出

手机操作系统设计中,对前台任务的时延要求是比较苛刻的。比如Android系统,谷歌花了大精力在优化前台任务的时延,使得用户操作手机上app时,可以无卡顿。

但是前台任务一旦执行fsync调用,有时候会卡在这个调用等待很长时间,fsync才会返回,这样fsync一旦耗时,前台任务就耗时,轻则用户操作手机时,会感受到卡顿现象。重则,Android框架层会触发watchdog事件,然后引发安卓自身重启。

看来必须要优化fsync耗时了。

优化工作开展

紧跟业务

首先我们的性能优化工作必须紧跟公司项目组业务。能够快速熟悉并按照公司业务特点做事,这比单纯的技术突破更重要。

而我们项目组的业务特点:就是通常互联网公司的开发模式,讲究做事短,平,快,不会给你太多时间做技术创作研究,另外性能工作有个特点,优化效果要用性能数据去证明。

经过分析调研该fsync耗时问题,发现是ext4+jbd2架构方面的缺陷导致的,具体如下:

ext4里面的fsync执行到最后一步时,需要等待jbd2把该fsync'er对应的事务给处理完毕,才能返回。如果jbd2恰巧处在高负荷的任务工作状态时,jbd2就无法快速返回,那么fsync不得不做漫长等待工作,结果造成了fsync自身的耗时。

这个问题是ext4里面的fsync和jbd2强耦合造成的,社区ext4 maintainer ted也承认是这个强耦合是ext4的一个架构方面的缺陷,目前不好调整它。

所以面对这个棘手的fsync耗时问题,只有采取通用的迭代式开发模式了,先着力突破解决一个问题,快速出个优化方案第一版,然后再迭代不断持续地去优化该fsync耗时问题。

异步discard优化

经过调研,发现用户那边的一个问题场景是在清理删除一些小文件后,再操作手机会有卡顿现象出现。对现场的bugreport log分析,发现卡顿正是由于fsync耗时引起的,而fsync慢是由于jbd2里面执行了很多ext4实时discard工作。

执行单个discard,并不耗时,但是在删除很多小文件后,jbd2 commit线程里面就会积累很多这样的discard工作请求,需要jbd2去完成。这样jbd2工作耗时,导致了fsync也跟着耗时了。

有了详细地问题原因结论后,下来想出了第一个优化方案:异步discard。

discard工作是Linux存储领域经常讨论的一个热门优化课题。在有些存储芯片上,累计的大量discard命令的处理是比较耗时的。但是还是得必须做discard工作的,因为该工作对于flash芯片的保养维护,存储IO性能优化方面还是很重要的。

所以经过精心设计,又加上本地的性能测试效果验证,发现异步discard的确可以提升fsync的性能,同时又能满足flash芯片必须及时做discard工作的需求。

技术方面的成长

1:通过该优化方案,使得我对存储芯片做discard的过程,还有ext4 discard触发的用户场景和整个工作流程都有深入的熟悉和掌握了。

2:对存储芯片如何做trim工作有了熟悉。这个涉及到存储性能优化工作的特色:可以跟存储芯片厂商密切配合,对存储芯片工作机制也会熟悉的。因为我们的业务是做存储性能优化的,所以很关注对存储芯片做完异步discard后,究竟过多久会带来IO性能的提升,答案是在存储芯片做完gc后,下来再测试存储性能,就会有提升。

需要指出的是该优化方案,还使得我们存储团队收获了第一篇能够发表在国际顶级会议:acm-mobi上的论文,向公司证明了我们存储团队的技术实力。

sqlite数据库 io优化

前一个优化方案部署完后,接着又发现用户手机还是经常报fsync卡顿问题。于是经过对手机操作系统fsync下发的调研,又发现了手机操作系统存储方面的一大特点:

手机操作系统里面大部分写都是数据库sqlite的单笔小量数据的频繁同步随机写(就是write+fsync)。

所以用户在日常使用手机时,尤其是重度使用时,用户态sqlite会频繁下发fsync给内核,fsync触发次数多了,那么必定会加重单次fsync耗时的。所以下来该优化sqlite的fsync调用次数了。

经过对sqlite代码的调研,发现sqlite数据库的journal defaul mode和sync default mode都是可以优化的。

sync default mode目前是full ,该模式下会频繁下发fsync的,可以换成normal模式的,这样对于wal的数据库,可以只在checkpoint的时候,做fsync工作,其他时候不需要做了。

journal default mode目前是truncate, 可以改成persist的。这样可以减少数据库IO方面的元数据写入量。(通过打开底层ftrace log,可以清晰地看到改成persist后,sqlite的元数据写入量会减少很多)。

经过对sqlite io的优化后,系统的下发fsync次数的确减少了,fsync耗时问题又得到了优化。

技术方面的成长

对sqlite数据库日志方面的设计思路和工作特点,以及与ext4文件系统搭配的缺陷问题,都有了比较深入地理解和掌握。

ps:

从上面的异步discard优化效果调研,还有sqlite性能优化,还有下面的fsync优化工作,包括之前的ext4碎片整理方案,这些性能优化无不诠释了存储性能优化工作的一大特点:

和解稳定性问题有一个大的区别,稳定性问题多是系统某个地方出问题了,我们fix它,不让它出故障就行了。解稳定性问题很多时候很难有系统整体架构方面的视野观。

但是存储性能优化则不一样了,我们搞个性能优化方案,往往不仅仅关注文件系统本身,要关注的是整个IO栈,而且还会横向关注比较不同文件系统间的设计差异。这样对存储整体设计架构方面,自身会开拓不少视野。

比如部署异步discard方案,不仅仅要关注内核软件IO栈,还有跟存储芯片厂商沟通,关注存储芯片里面的实际优化效果。

sqlite方面,要做性能优化,会关注它的整体设计架构方面缺陷,比如它和ext4文件系统搭配起来的双日志性能缺陷,于是横向比较f2fs,这个新文件系统的atomic写怎么解除双日志缺陷。

被推翻的走捷径的优化

前面两个优化做完后,发现用户手机还是会有fsync卡顿问题出现。

前面已经说了这个ext4 fsync耗时其实关键是等待jbd2事务commit完成这一步比较耗时,那么能否不等待jbd2 commit事务完成,直接返回呢,这样fsync工作跟jbd2就没有关系了,然后再做成手机低电量时,恢复fsync的正常执行。

带着这样的疑问,调研了异常掉电时文件系统一致性问题,还有ext4日志对于保障文件系统数据和元数据一致性问题方面的的东西,最后结论是还是不要采取这种走捷径的优化思路。

理由如下:

不能强行依赖手机电量信息去调整fsync的行为,fsync行为一旦调整,文件系统日志行为也跟着被变更,万一电量计算不准或者手机异常掉电重启,文件系统的一致性就有可能会遭到破坏。

有人可能会说为啥不在手机内核panic时,或者异常掉电之前那段时间,强行执行下sync操作,同步下文件系统的数据。这样做也是有风险的,首先手机上的存储器件有时候会出现各种意外问题,执行sync操作时,可能会耗时卡住。

这个时候,异常掉电时,sync操作可能不会及时刷完所有的数据到盘上。另外内核panic因为sync操作耗时卡住时,芯片watchdog不会给os这么充足时间的,会直接复位重启的。

所以最好还是不要采取这种走捷径的优化。

技术方面的成长

对ext4如何借助jbd2来实现日志功能,以及日志功能怎么保障文件系统元数据一致性,还有异常掉电文件系统丢数据问题有了更深刻地理解和掌握。

结合社区jbd2相关patch的优化

做Linux存储性能优化工作,需要经常紧跟一些开源存储社区动态,比如要关注ext4/f2fs mail list上面每天进的优化patch,关注内核lwn社区上面最新发表的内核方面文章,要会充分利用这些开源资源,为自己的kpi考核服务。

凑巧ext4社区上发布了优化jbd2工作性能的patch:jbd2_inode dirty range scoping,这个patch经过我的分析后,认为可以优化我们碰到的fsync耗时问题。

经过对该patch代码的深入研读,结合着长期跟踪分析这个ext4 fsync 耗时问题的工作经历,

终于发掘到了我们的手机系统引发fsync耗时的又一大原因

手机的ext4文件系统会被设置成order 日志模式 + 物理block延迟分配,而做这样的设置后,会加重单次fsync耗时的。因为order模式下,jbd2在commit事务时不得不去等待文件脏数据落盘完成,

这一等待是比较耗时的,尤其在ext4开启延迟分配后,系统的刷脏页时间周期会延长至30秒,这样在内核回写线程被周期性唤醒后,需要刷系统累积的大量脏页时,还得做耗时的物理block分配工作,这样刷脏页就会消耗时间,

这样jbd2也不得不卡在等刷脏页完成这步。然后呢,fsync也不得不跟着卡住等待。

而社区这个changes,正是优化这个因jbd2等待脏页回写完成而导致的性能问题的。通过对该patch的学习,我又发现了该patch的不足之处,又做了进一步地优化。结果这个优化方案完成后,手机的fsync卡顿又减少了。

技术方面的成长

1:对jbd2 order工作模式和内核脏页回写线程,以及ext4延迟分配的工作机制和缺陷都有了深刻地理解。

2:结合社区patch,又发现了两点不足之处,做出的改进如下:

1)区分dirty ranges for each of the current and next transaction

2)去掉内核writeback线程的第一个blk request plug。

进一步的优化

前面一些优化方案部署后,还是会存在有fsync耗时问题。看来需要继续优化了。

1:尝试调研jbd2日志模式由order变为writeback

目前的fsync耗时问题很多都是jbd2工作在order模式下引发的,能否尝试换成writeback模式呢,这样jbd2就不需要等待脏数据回写完成了,自身工作负担也减轻很多。

经过对手机业务场景的调研,发现现在手机里面都是加密文件系统,改成writeback模式不用担心数据安全泄密问题的。这样改成writeback的一个路障被打通了。

接下里对社区历年来的jbd2提交patch又做了调研,最后发现还不能改成writeback模式。

因为除了有stale data问题之外,还会有数据稳定性问题。下来又在ext4社区跟ted咨询了下,结果确认确实会存在数据稳定性风险的。

2:比较ext4在日志保护文件系统数据稳定性方面和f2fs的区别

组内同时也在做f2fs文件系统的工作,有机会在文件系统数据稳定性方面对ext4和f2fs做个对比分析。

ext4是原地更新写,所以得借助jbd2和事务的思想,去实现日志功能,保证异常掉电时的文件系统一致性。

f2fs采用了较新的文件系统设计思想,采用cow思想,这样可以部分不需要借助日志功能,也可以保证异常掉电时的文件系统一致性。

有篇lwn的文章更好地诠释了这方面的差别:

Soft updates, hard problems

Soft updates, hard problems [LWN.net]

所以对f2fs如何保证掉电文件系统一致性这方面也做了调研,顺便熟悉了f2fs文件系统的设计架构。

3:开启dioread_nolock的优化

意外地发现这个dioread_nolock开启后,可以切断fsync与内核writeback线程下发的异步io请求之间的联系,因此可以间接提升fsync的性能。

而我们的手机内核版本在kernel-4.9以后,dioread_nolock已经等同于变成空操作了,开启它,对系统的行为没有一点影响,除了可以切断fsync跟内核脏页回写线程的联系。

只是开启后,会有一点负作用就是:会比以前增加点jbd2产生的元数据写入量。

仔细分析了手机的业务场景,发现能解决fsync耗时带来的收益远大于产生的这些额外的元数据写入量。

所以开启这个dioread_nolock后,jbd2不需要等待文件脏数据回写完成了,fsync跟内核脏页回写线程间的联系被切断了fsync耗时性能就得到进一步大地提升了

4:参与ext4社区fast_commit功能开发

ext4社区下来也发现了这个fsync和jbd2强耦合的缺陷,虽然上面的dioread_nolock能解决这个缺陷导致的fsync问题,但是还解决地不够完美,毕竟有点负作用:带来一些额外的元数据写入量。

所以社区maintainer ted开始推动解决这个强耦合缺陷,我也在工作之外业务时间,有幸参与了部分开发工作,帮着ted和一个印度工程师review fast commit代码,提一些建设性的问题。

毕竟这个fast_commit功能一旦实现好,对我们的手机前台任务卡顿问题也会有所优化的。

通过和ted的邮件交流,使我对文件系统日志方面工作机制又有了深刻地理解和认识。

那些年解的疑难性能问题 --- ext4_fsync优化相关推荐

  1. 那些年解的疑难性能问题 --- ext4碎片整理

    引子 年轻时候的我们,觉得疑难问题大都是技术方面的问题.觉得自己解个疑难高深技术问题,就很了不起似的. 但是随着工作经历的不断丰富,我们会发现国内IT企业搞法,光拼技术,很容易被年轻人赶上的.因为国内 ...

  2. 超级干货:3个性能监控和优化命令详解

    小编为大家整理出了三个有关性能监控和优化命令详细讲解,别看只有三个,但不影响他噎啊,本篇文章很长,涉及top命令.free命令和vmstat命令,真的是很详细的讲解,希望能帮到大家,另外还有两条相关的 ...

  3. 长文详解材料阻燃性能试验方法

    长文详解材料阻燃性能试验方法 材料阻燃性能试验方法 阻燃材料燃烧试验的目的在于评定它的燃烧特性,即是否容易着火.着火后是否延燃,以及是否冒烟和释放毒气等.本文主要介绍了材料阻燃性能的测试方法. 1.火 ...

  4. java如何监控cpu耗时_超级干货:3个性能监控和优化命令讲解

    原标题:超级干货:3个性能监控和优化命令讲解 小编为大家整理出了三个有关性能监控和优化命令详细讲解,别看只有三个,但不影响他噎啊,本篇文章很长,涉及top命令.free命令和 vmstat命令,真的是 ...

  5. VMware vSphere 性能优化设计经验+优化方法 | 周末送资料

    VMware vSphere 性能优化设计经验+优化方法 | 周末送资料 https://mp.weixin.qq.com/s?__biz=MjM5NTk0MTM1Mw==&mid=26506 ...

  6. 16apsk matlab,与低计算复杂度解映射相结合的16APSK星座优化

    摘  要: 提出一种在新的简化的解映射方法下,以星座图上所有信号点距离解映射门限的最小距离的最大化为目标函数的星座图优化方法.仿真比较了在优化设计的星座映射下,传统的解映射算法和所提出的解映射的误码性 ...

  7. 推理芯片的性能建立在优化的存储子系统设计上

    推理芯片的性能建立在优化的存储子系统设计上 Inference chip performance builds on optimized memory subsystem design 好的推断芯片可 ...

  8. linux 性能 管理 与 优化

    一.影响Linux服务器性能的因素 操作系统级:CPU.内存.磁盘I/O带宽.网络I/O带宽 程序应用级 二.系统性能评估 影响性能因素   评判标准 好   坏   糟糕 CPU   user% + ...

  9. 九、OLTP 性能调整与优化--结语

    OLTP性能调整与优化--结语 根据软件生命周期的瀑布模型,应用程序的性能在其设计阶段就已经有了质的定性.如果在应用程序开发完成之后才想到优化,一般就只能治标不治本,在遇到严重的性能问题时,甚至需要将 ...

最新文章

  1. GitHub 又一开源神器!写代码、搜问题,全部都在「终端」完成!
  2. SpingMVC类型转换
  3. android 蓝牙打印格式,Android蓝牙打印格式排版
  4. 软件测试作业2:在敏捷宣言遵循的12条原则中挑选1条你感兴趣的原则进行风险评估
  5. 数字摄像头测试软件,图像测量软件(Camera Measure)
  6. [bzoj1026] [SCOI2009]windy数
  7. Android 2019最新面试实战总结
  8. H5页面适配 iPhoneX
  9. intellij idea 和 maven的自己的理解和安装配置
  10. 计算机思维导论在线测试题库,计算机导论题库有答案.docx
  11. 用matlab写出信源熵,计算离散信源的熵matlab实现
  12. labview霍夫曼编码_毕业设计 基于LabVIEW的编码的设计与仿真—信源编码
  13. 微信 小程序 python 渲染_微信小程序python用户认证的实现
  14. echarts 设置地图默认缩放比例 尺寸
  15. 慧都与数据库厂商Devart进一步提升合作层次
  16. Anchor-Free系列之CornerNet: Detecting Objects as Paired Keypoints
  17. Eclipse执行junit测试时出现Errors occurred during the build. Errors running builder 'Integrated External Too
  18. 用关键词搜索店铺列表详情
  19. 狗狗自带餐具能有多可爱
  20. C语言进程——进程间的通信方式

热门文章

  1. 华为认证存储方向冷门吗?这个存储证考下来有啥用?
  2. 远程代码注入及DLL注入教程(InlineHook)---植物大战僵尸为例
  3. 销轮计算器——走出阶梯轴的「笨拙」困境
  4. 【Email】Java发送邮件接口与配置类
  5. 矛盾方程的最小二乘解
  6. 如何把在一些管家软件下载的谷歌卸载干净(谷歌卸载不干净、安装不成功的原因,谷歌首页被360篡改)
  7. [SECURITY]--01
  8. 不念过往,不畏将来——告别曾经
  9. 关于vec(ABC)=(C ^{T}⊗A)vec(B)的计算
  10. 等额分期付款公式推导