mysql fsync_mysql fsync

mysql fsync_mysql fsync标签:1介绍数据库系统从诞生那天开始,就面对一个很棘手的问题,fsync的性能问题。组提交(groupcommit)就是为了解决fsync的问题。最近,遇到一个业务反映MySQL创建分区表很慢,仔细分析了一下,发现InnoDB在创建表的时候有很多fsync——每个文件会有4个fsync的调用。当然,并不每个fsync的开销都很大。这里引出几个问题:(1)问题1:为什么fsync开销相对都比较大…

大家好,又见面了,我是你们的朋友全栈君。

标签:

1 介绍

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

20181005090828048041.jpg

这里引出几个问题:

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

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

20181005090828437665.jpg

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

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

2 原因分析

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

2.1 测试程序1

Write page 0

Sleep 5

Fsync

用blktrace跟踪结果如下:

20181005090829048954.jpg

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

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

20181005090829457131.jpg

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

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

块2405:

20181005090829828201.jpg

#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:

20181005090830451208.jpg

的确是提交块。

2.2 fsync的实现

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

函数ext3_sync_file:

20181005090830802748.jpg

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

20181005090831137687.jpg

从代码来看,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

20181005090831563441.jpg

20181005090831896428.jpg

从第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日志,也就不需要等待事务提交完成。

20181005090832247968.jpg

下面验证一下该想法。

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修改。

20181005090832608296.jpg

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

20181005090832869998.jpg

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

3 优化

如何优化fsync?是个难题。

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

作者:YY哥

出处:http://www.cnblogs.com/hustcat/

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/138169.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • CodeForces 10D. LCIS 最长公共上升子序列模板题 + 打印路径

    CodeForces 10D. LCIS 最长公共上升子序列模板题 + 打印路径

  • lede旁路由设置方法

    lede旁路由设置方法lede固件号:2.361.把网络–>接口里面wan口删除2.推荐新建lan口,把原来的lan停用3.新lan口配置:静态地址ipv4地址:主路由地址ipv4子网掩码:255.255.255.0ipv4网关:主路由地址使用自定义的DNS服务器:主路由地址关闭DHCP如果出现访问国内网站巨慢,慢到离谱那种请在旁路由执行以下代码iptables-tnat-IPOSTROUTING-jMASQUERADE并在网络—>防火墙中勾选丢弃无用数据包…

  • 关于开源的RTP——jrtplib的使用

    关于开源的RTP——jrtplib的使用

    2021年11月28日
  • 51单片机学习笔记:合并1602和12864液晶排插接口

    51单片机学习笔记:合并1602和12864液晶排插接口 今天成功合并1602和12864液晶排插接口! 码出来分享下 上面这2个图是1602和12864液晶的排插接口,一般的单片机开发板上都会有仔细观察发现他们的插口大多是相同的, 对于第三脚的对比度调节,1602和12864液晶在硬件上是相反的(1602是低电位方向对比度增强,12864是高电位方向对比度增强),但他们接口位置相同,所以一个10K左右的3脚电位器…

    2022年10月20日
  • 修改apache服务器端口号_apache修改端口号

    修改apache服务器端口号_apache修改端口号一、修改/etc/httpd/conf/httpd.conf文件中的监听端口号Listen80把80修改成需要的号,如8000,即Listen8000二、查看SELinux下http相关端口#semanageport-l|grephttphttp_cache_port_ttcp3128,8080,8118,10001-10010http_cache_po

  • dom4j java对象_dom4j解析XML成对象

    dom4j java对象_dom4j解析XML成对象最近不太忙,发现现在服务之间的交互都是通过xml进行的,所以今天理了一下xml的两种解析方式。首先是最流行的dom4j解析。先解析,然后通过反射转成对象。用到的jar:dom4j-1.6.1.jarjaxen-1.1.1.jar1.xml字符串转成对象:class=”java”name=”code”>/***解析XMl字符串数据,转化成对象,并返回*@paramxmlxml字符串…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号