标签:
1介绍
数据库系统从诞生之日起,就面临着fsync性能问题这一棘手的问题。 组提交(group commit )是为了解决fsync的问题。 最近遇到了反映MySQL创建分区表很慢的业务。 通过仔细分析,我们发现InnoDB在创建表时,每个许多fsync——文件都有四个fsync调用。 当然,并不是所有的fsync开销都很大。
这里提出几个问题:
)问题1 )为什么fsync的开销相对较大? 你做了什么?
)2)问题2 :在第一次open数据文件后,可以看到第二次fsync的时间远远小于第一次fsync的调用时间。 为什么?
)3)问题3 )是否可以优化fsync?
这些疑问,一起认识一下fsync吧。
2原因分析
首先,通过测试程序学习fsync在块级的基本流程。
2.1测试程序1
写页面0
第五季
自由同步
使用blktrace跟踪的结果如下。
上半部分的红色框内pwrite是块级的流动,下半部分的黄色框内fsync是块级的流动,中间正好相差5秒。
4722712是对应于测试文件第一块的扇区号,590339 (块号)8=4722712 (扇区号)。
无论是pwrite还是fsync,开销都是向驱动程序发送IO请求和完成IO之间的开销,即从设备驱动程序启动。 大约占整个系统调用1/2的开销。
另外,调用fsync时,发生了3次块层IO,开头扇区分别为19240、19248、19256,可知在物理上是3个连续的块。 实际上,这3个块是内核线程kjournald所写的日志,分别记述了块(2405 )、数据块(2406 )、提交块(2407 )。 为了验证,我们来看看这三个块的实际数据。
方框2405 :
# define jfs _ magic _ number0x c03b 3998 u
#define JFS_DESCRIPTOR_BLOCK 1
#define JFS_COMMIT_BLOCK 2
前四个字节是JFS_MAGIC_NUMBER,后跟block type:JFS_DESCRIPTOR_BLOCK。
方框2407 :
确实是提交区块。
2.2实现fsync
fsync的开销很大,让我们看看代码吧。
函数ext3_sync_file :
函数log_start_commit负责启动kjounald内核线程,log_wait_commit等待jbd事务提交完成。
从代码的角度看,fsync的主要开销是调用log_wait_commit后的等待。 这意味着,在kjournald提交事务之前,fsync不会返回。
到目前为止,fsync开销的主要产生源是: (1)硬件驱动层的开销; )2)写ext3日志。
此外,如果log_start_commit返回0,则fsync不会等待事务提交完成。 到此为止,我们已经基本上确认了第二次fsync的开销为什么那么小,——是否没有提交wait事务。
验证这个想法。 为了便于调试,打开了内核jbd调试日志。
2.3测试程序2
写页面0
自由同步
写页面0
自由同步
写页面1
自由同步
写页面2
自由同步
从第二个红框的日志来看,第二次的fsync的情况下,因为确实没有wait,所以开销这么小,但是其他三次的fsync都调用了log_wait_commit函数。
问题4 :第二次的fsync为什么不调用log_wait_commit?
因为在挂载文件系统时,写data=writeback,即写数据本身不写jbd日志。 第二次pwrite不引起文件扩展,只修改ext3 inode的i_mtime,i_mtime只正确到second。 也就是说,第二次的pwrite不会引起inode信息的变更,所以不生成jbd日志,也没有必要等待事务提交完成。
验证一下这个想法吧。
2.4测试程序3
写页面0
自由同步
休眠1秒
写页面0
自由同步
写页面1
自由同步
写页面2
自由同步
在第二次pwrite之前,在sleep 1秒钟内保证ext3 inode的i_mtime的修正。
想法得到了证实,第二次fsync的时间回到了正常水平。
可以看到,第二次fsync调用将提交新事务,然后调用log_wait_commit等待事务完成。
3优化
如何优化fsync? 是个很难的问题。
)1)系统减少对fsync的调用。
作者: YY哥
资料来源: http://www.cnblogs.com/hustcat/
著作权在作者和博客之间是共享的,所以欢迎转载。 但是,未经作者同意,必须保留本段声明,并在文章页面的明显位置提交原文链接。 否则,保留追究法律责任的权利。