zoukankan      html  css  js  c++  java
  • 深入理解Fsync

    1 介绍

    数据库系统从诞生那天开始,就面对一个很棘手的问题,fsync的性能问题。组提交(group commit)就是为了解决fsync的问题。最近,遇到一个业务反映MySQL创建分区表很慢,仔细分析了一下,发现InnoDB在创建表的时候有很多fsync——每个文件会有4个fsync的调用。当然,并不每个fsync的开销都很大。

    clip_image002

    这里引出几个问题:

    (1)问题1为什么fsync开销相对都比较大?它到底做了什么?

    (2)问题2:细心的人可以发现,第一次open数据文件后,第二次fsync的时间远远小于第1次调用fsync的时间,为什么?

    clip_image002[5]

    (3)问题3能否优化fsync?

    来着这些疑问,一起来了解一下fsync。

    2 原因分析

    我们先通过一个测试程序来学习一下fsync在块层的基本流程。

    2.1 测试程序1

    Write page 0

    Sleep 5

    Fsync

    用blktrace跟踪结果如下:

    clip_image004

    上半部红色框内为pwrite在块层的流程,下半部黄色框内为fsync在块层流程,中间刚好相差5秒。

    4722712为测试文件的第1个block对应的扇区号,590339(block号) * 8=4722712(扇区号)。

    clip_image006

    无论是pwrite,还是fsync,主要的开销都发生IO请求提交给驱动和IO完成之间,也就是说开自设备驱动。差不多占了整个系统调用的1/2的开销。

    另外,可以看到调用fsync时,发生了3次块层IO,起始扇区分别是19240、19248和19256,物理上3个连续的块。实际上这3个块为内核线程kjournald写的日志,分别描述块(2405)、数据块(2406)和提交块(2407)。为了验证,不妨看一下这三个块的实际数据。

    块2405:

    clip_image008

    #define JFS_MAGIC_NUMBER 0xc03b3998U

    #define JFS_DESCRIPTOR_BLOCK 1

    #define JFS_COMMIT_BLOCK 2

    开始的4个字节为JFS_MAGIC_NUMBER,然后是block type:JFS_DESCRIPTOR_BLOCK。

    块2407:

    clip_image010

    的确是提交块。

    2.2 fsync的实现

    既然fsync的开销很大,就来看看代码吧。

    函数ext3_sync_file:

    clip_image012

    函数log_start_commit负责唤醒kjounald内核线程,log_wait_commit等待jbd事务提交完成。

    clip_image014

    从代码来看,fsync的主要开销在于调用log_wait_commit后的等待。也就是说fsync要等待kjournald把事务提交完成,才会返回。

    到这里,我们已经知道了fsync开销的主要来源:(1)硬件驱动层的开销;(2)ext3写日志。

    另外,当log_start_commit返回0时,fsync就不会等待事务提交完成。到这里已经基本可以确认第2次fsync的开销为什么那么小了——没有wait事务提交。

    下面验证这一想法。为了方便调试,打开了内核jbd debug日志。

    2.3 测试程序2

    Write page 0

    Fsync

    Write page 0

    Fsync

    Write page 1

    Fsync

    Write page 2

    Fsync

    clip_image016

    clip_image018

    从第2个红框的日志来看,第2次fsync时,的确是没有wait的,所以开销这么小,而其它3次fsync都调用了log_wait_commit函数。

    问题4:第2次fsync为什么不会调用log_wait_commit

    因为挂载文件系统的时候,data=writeback,即写数据本身不会写jbd日志。第2次pwrite没有引起文件扩展,只会修改ext3 inode的i_mtime,而i_mtime只精确到second,也就是说第2次pwrite不会引起inode信息改变,所以,不会生成jbd日志,也就不需要等待事务提交完成。

    clip_image020

    下面验证一下该想法。

    2.4 测试程序3

    Write page 0

    Fsync

    Sleep 1 second

    Write page 0

    Fsync

    Write page 1

    Fsync

    Write page 2

    Fsync

    在第2次pwrite之前,sleep 1秒钟,保证ext3 inode的i_mtime修改。

    clip_image022

    想法被证实了,第2次fsync的时间回到正常水平。

    clip_image024

    可以看到,第2次fsync调用提交了新的事务,并调用了log_wait_commit等待事务完成。

    3 优化

    如何优化fsync?是个难题。

    (1)系统减少对fsync的调用。

    (2)ext3日志放在更快的存储介质,参考http://insights.oetiker.ch/linux/external-journal-on-ssd/


    作者:YY哥
    出处:http://www.cnblogs.com/hustcat/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    Windows10 + eclipse + JDK1.8 + Apache Maven 3.6.0 + dl4j深度学习环境配置
    vector,deque,list的区别和使用
    extern C的用法解析
    向jupyter notebook加入Anaconda3中已添加的虚拟环境kernel
    TensorFlow学习
    windows10+Python3.6+Anaconda3+tensorflow1.10.0配置和安装
    torchvision
    无oracle客户端仅用plsql连接远程oracle
    poj 3463 Sightseeing(次短路+条数统计)
    10.11 noip模拟试题
  • 原文地址:https://www.cnblogs.com/hustcat/p/3283955.html
Copyright © 2011-2022 走看看