MySQL中I/O出现错误问题原因是什么


MySQL中I/O出现错误问题原因是什么?这个问题可能是我开发云主机域名们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧!最近使用sysbench测试MySQL,由于测试时间较长,写了一个脚本按prepare->run->cleanup的顺序在后台跑着。跑完后察看日志发现一个问题,MySQL服务的错误日志中出现多条类似以下信息的报错:看起来是I/O出现了错误,但MySQL进程并未崩溃,sysbench客户端也没有报错。根据报错的时间记录以及脚本输出的各个阶段的时间点对比,确定了当时脚本正在执行的命令为:重新手动执行一遍这个用例,却没有再出现同样的情况。但是用脚本执行却依然能够发现这个错误信息。初步怀疑是run和cleanup之间不能间隔太久才会触发这个问题。由于执行一遍100G数据量的时间较长,重现代价较大,先尝试缩减用例数据量。将—table-size=4000000修改为2000000,此时执行脚本,又不会触发这个问题了,最后将—table-size=3000000可以稳定触发又能减少部分重现时间。为了确认是否间隔太长会导致不能复现,修改脚本在run和cleanup两个阶段之间sleep 10秒,果然不会触发这个错误信息。修改为sleep 5秒则还能触发,不过报错条数已有所减少。察看对应版本mysql5.7.22的代码,发现这个报错只有一个位置:fil0fil.cc文件的第5578行fil_io()函数内。 直接使用gdb调试,在这个位置加上断点,并执行可复现的脚本,得到以下堆栈:很明显这是后台线程在做insert buffer merge操作。此时发现space->stop_new_ops为true,也就是要处理的页面所属的space正在被删除。为什么会去操作正在被删除的space呢?这需要调查下insert buffer功能、insert buffer merge的流程以及删除表的流程。insert buffer是一种特殊的数据结构(B+ tree),当辅助索引页面不在缓冲池中时,它会将更改缓存起来,稍后在页面被其他读取操作加载到缓冲池中时合并。MySQL最初引进这个功能的时候只能缓存insert操作,所以叫做insert buffer,现在这些操作可以是 INSERT, UPDATE, or DELETE(DML),所以改叫做change buffer了(本文依然以insert buffer描述),但源码中依然以ibuf作为标识。这个功能把若干对同一页面的更新缓存起来,合并为一次性更新操作,减少了IO,并转化随机IO为顺序IO,这样可以避免随机IO带来性能损耗,提高数据库的写性能。当buffer page读入buffer pool时,就会进行insert buffer merge。主要有几个场景会出现merge过程:当页面被读入缓冲池时,读取完成后先进行ibuf的merge,然后页面才可用;merge操作作为后台任务执行。 innodb_io_capacity参数可设置InnoDB后台任务每次merge过程的页面数上限;在崩溃恢复期间,当索引页被读入缓冲池时,将执行对应页的insert buffer merge;insert buffer具有持久性,系统崩溃不会导致它失效。重启后,insert buffer merge操作将恢复正常;服务器关闭时可使用—innodb-fast-shutdown = 0强制进行ibuf的完全合并。我们这次的问题很明显属于第二种情况。innodb主线程(svr_master_thread)会每隔一秒主动进行一次insert buffer的merge操作。先判断过去1s之内服务器是否发生过活动(插入元组到页面、undo表上的行操作等),如果发生过,则merge的最大页面数为innodb_io_capacity设定的5%。如果没有则merge的最大页面数为innodb_io_capacity设定的值。innodb主线程(svr_master_thread)merge的主流程如下:主线程从ibuf树的叶子节点读取页号和space号,并记录到一个二元数组中(未加锁);主线程对二元组中space进行检测是否在表空间缓存中,如不在,说明已经被删除了,删除对应ibuf的记录;主线程判断是否对一个正在删除的space进行异步读取操作,如果是,报错,并删除对应ibuf的记录,转到过程2继续下一个数组元素的判断;如果一切判断正常,主线程发出async io请求,async读取需要被merge的索引页面;I/O handler 线程,在接受到完成的async I/O之后,进行merge操作;进行merge的时候调用fil_space_acquire对space->n_pending_ops进行自增。避免删除操作并发;执行完毕后调用fil_space_release对space->n_pending_ops进行自减。对fil_system->mutex加锁,设置sp->stop_new_ops = true,标记space正在删除,不允许对它进行新操作,然后对fil_system->mutex解锁;对fil_system->mutex加锁,检测space->n_pending_ops,对fil_system->mutex解锁。如果检测到大于0,意味着还有依赖的操作未完成,睡眠20ms后重试;对fil_system->mutex加锁,检测space->n_pending_flushes和(*node)->n_pending ,对fil_system->mutex解锁。如果检测到大于0,意味着还有依赖的I/O未完成,睡眠20ms后重试;此时认为已经没有冲突的操作了,刷出所有脏页面或删除所有给定的表空间的页面;从表空间缓存删除指定space的记录;删除对应数据文件。情况很明确了,主线程获取ibuf的(space,page)的过程与删除操作执行的过程并没有锁保证互斥,只有async I/O完成之后的merge操作与删除操作才有互斥。如果后台线程开始ibuf merge并已经执行过了第2步的检测,但还没有执行到第3步检测,此时用户线程开始做删除表的操作,并设置好stop_new_ops标记但还没有执行到第5步删除表空间缓存,就会出现这个错误信息。两线程的交互如下图所示:不出意外的话,在打中断点时必然有线程在执行对应表的删除操作。果然我们可以发现如下堆栈:为buf_read_ibuf_merge_pages、buf_read_page_low、fil_io新增一个参数ignore_missing_space。表示忽略正在删除的space,默认为false,当ibuf_merge_pages调用的时候置为true。在fil_io报错处额外判断该参数是否为true,是则不报错,继续其他流程。或者直接在buf_read_ibuf_merge_pages调用buf_read_page_low时传入IORequest::IGNORE_MISSING参数。具体代码参考MariaDB commit:8edbb1117a9e1fd81fbd08b8f1d06c72efe38f44察看相关信息,这个问题是修改Bug#19710564时删除表空间版本引入的。MySQL Community Server 5.7.6引入,版本5.7.22尚未修复,版本8.0.0已修复。MariaDB Server 10.2受影响。MariaDB Server 10.2.9, 10.3.2已修复可优化一下性能:在buf_read_ibuf_merge_pages中记录下出错的space id,循环的时候判断下一个page的space id,如果space id是相同的,直接删除对应ibuf的记录(当前分配的最大space id记录在系统表空间,space id占4个字节,低于0xFFFFFFF0UL,分配时读取系统表空间保存的值,然后加一,具有唯一性)。end:对于知识点我就介绍到这里了,写的有点快,可能有不足之处,还望多多交流指正,希望能帮到大家。感谢各位的阅读!看完上述内容,你们对MySQL中I/O出现错误问题原因是什么大概了解了吗?希望文章内容对大家有所帮助。如果想了解更多相关文章内容,欢迎关注开发云行业资讯频道。

相关推荐: MySQL存储引擎基础知识

在之前的文章中我们说过MySQL事务,现在开发云主机域名大家都应该知道了MySQL事务了吧,还记得事务的ACID原则吗?不记得的童鞋可以回顾一下《MySQL之事务初识》,其实呀,更严谨一点的话,应该是MySQL InnoDB存储引擎,因为在MySQL中,只有I…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 06/10 22:10
下一篇 06/10 22:23

相关推荐