DBA某数据库集群每日17:00左右会出现一个性能陡降的现象,在10~20秒内主库出现大量慢查询。这些查询本身没有性能问题,也没有任何关联,可以认为是由于数据库系统负载较重,由于并发导致的慢查询。通过对全日志的梳理,已经查明每日17:00左右导致主库性能下降的问题原因是该时段在执行某定时任务中的一个Update语句。该update语句一次性会对约70万个row进行更新,引发大量数据库写入,是导致数据库性能下降的直接原因。

1、问题描述 但是还存在一个疑点,那就是该定时任务每天会执行三次,零点,12点和17点,数据的更新量几乎一致,其中12点和17点均是业务的高峰期,为何只有下午17点会出现大量慢查询,而上午12点数据库受到的影响相对较小,没有出现慢查询呢? 2、监控数据分析 DBA对当时数据库系统的状态进行了分析,12点与17点都存在一个突发的大量数据写入,对比两个时间段的innodb性能参数,可以发现:

(1) 两个时间段Innodb log buffer均有一个突发的写入

(2) 两个时间段innodb_log file均有一个突发的写入

注:对int32高于2^31的数据都显示为负数,13:30左右的陡降为监控系统的bug,请忽略。

分析 (1),(2) 说明该时间点有一个影响行数较高的突发的写入操作。

(3) 12点时innodb buffer dirty page有一个突增,但17点左右innodb buffer dirty page 有一个突降

(4) 12点时innodb的数据文件写入速度维持在一个相对平缓的水平,而17点左右innodb的数据文件写入速度有一个突增。 注:对int32高于2^31的数据都显示为负数,13:30左右的陡降为bug,请忽略。

(5) 12点时系统IO的BI略有增长,但是不大,而17点时BI有非常大的增长,对系统IO性能有很大的影响。

分析 (3),(4)说明该时间点确实有大量数据写入,但是12点左右的时候数据以脏页的形式保存在buffer pool中,而17点的时候脏页被大量写入到磁盘中。通过(5)可以看出12点的时候脏页是在update操作结束后缓缓刷入磁盘,而17点的时候脏页被直接刷入磁盘。可见导致数据库性能陡降的原因就是脏页刷盘,12点的时候性能没有明显相加的原因就是没有突发的脏页刷盘。
3、InnoDB数据存储 InnoDB数据存储主要分为数据部分和日志部分。 数据部分称为tablespace,记录数据和索引数据都保存在tablespace中,最小物理存储单位是page。InnoDB中每一个page的默认大小为16K。tablespace一般使用文件来保存,5.1版本中可以将tablespace存放在磁盘裸分区中。总之innoDB数据存储的物理结构是一个以page为最小单位的数据空间。 相对于tablespace数据空间,innoDB通过一个log group作为日志空间。log group由至少两个日志文件组成,日志空间每一条记录都保存一个tablespace中数据的变化,称为为mini transaction。日志空间是一个环状的结构,写满后会从头部开始写入。每一条记录都会按写入日志的累积长度(单位为字节)分配一个记录号,称为Log Sequence Number (LSN)。与日志对应,数据空间中每一个page的头结构中也记录着该page对应的LSN,即表明了该数据的新旧程度。 InnoDB数据库的数据空间和日志空间都有两种存在形式,持久化在磁盘上的磁盘数据和内存中的buffer数据。 数据文件的buffer是由Innodb_buffer_pool_size定义的,缓存的是运行时正在被使用的数据空间page,其中被写请求更新,但没有同步到磁盘上page,称为dirty page; 日志文件的buffer是由Innodb_log_buffer_size定义的,缓存的是运行时正在被使用的日志空间page。日志buffer刷盘的策略由innodb_flush_log_at_trx_commit确定。 数据buffer和日志buffer在一些时机会同步到磁盘的对应空间中去,即flush。进行flush的时机包括三种:overflow,checkpoint和commit。 InnoDB认为数据是日志的一种冗余,所以日志写盘必须早于对应的数据写盘,这种思想在这三个时机都有体现。 overflow:log buffer是一个环状结构,最后一个记录写满后会从第一个位置开始写。日志记录被覆盖之前会被写入到日志文件中去。日志空间在磁盘上写入的方式也是环形队列方式,log group被写满后也会覆盖最早的日志记录。InnoDB的checkpoint机制能保证数据必定会在日志记录被覆盖之前写入到磁盘中去。 当data buffer写满后,InnoDB会使用LRU策略清除部分缓存。在清除每个buffer page之前都会检查该page的LSN是否比磁盘上最大的LSN大,即data buffer写盘速度是否写的比log buffer快。InnoDB不允许data buffer 比log buffer 写盘快,当这种情况发生时,InnoDB会触发log buffer的写盘,直到log buffer写盘进度比data buffer快才会进行data buffer page的写盘。 checkpoint:InnoDB有独立线程负责定期进行checkpoint。InnoDB使用一种叫做Fuzzy Checkpoint的策略,它并不保证所有数据都被完全同步到磁盘上,而是只能保证: (a) log buffer和data buffer不会超过buffer总量的一定阈值,这保证了buffer可用空间 (b) log buffer写盘进度比data 写盘快,InnoDB写盘基本原则 (c)确保日志文件中日志记录被覆盖前,日志记录对应的数据page一写先被写盘,确保保证log overflow时不存在没有同步到磁盘上的数据。 commit:commit的时候InnoDB只会对log buffer进行写盘,而不会写入对应的data buffer,这一过程交由overflow触发。

由于innodb对log的空间有预留策略,部分page使用还有其他的用途,实际可用的空间只有80%左右。 4、分析checkpoint增长情况 回到我们出现性能问题的数据库上来,该数据库InnoDB log大小为100M*2=200M,实际可用与保存日志空间约为160M.

分析innodb log的增长情况。采集了4月20日12点和4月21日17点的innodb状态数据。此数据通过show engine innodb status\G获得。 4月20日12点innodb log的增长情况: Update前:10-04-20 11:55:57 Log sequence number 1016 342557090 Log flushed up to 1016 342557090 Last checkpoint at 1016 302781061

Update后:10-04-20 11:56:12 Log sequence number 1016 427706865 Log flushed up to 1016 427706865 Last checkpoint at 1016 302792380

LSN增长了80M左右,checkpoint与最新LSN差距约120M,没有达到160M,所以checkpoint没有较大变化。

4月21日17点innodb log的增长情况: Update前:10-04-21 17:04:58 Log sequence number 1018 345302625 Log flushed up to 1018 345301911 Last checkpoint at 1018 243759516

Update后:10-04-21 17:05:14 Log sequence number 1018 426144696 Log flushed up to 1018 426144696 Last checkpoint at 1018 278852487

LSN增长约55M,但checkpoint与最新的LSN差距180M超过160M, log被写满,多出的20M log由上述checkpoint规则(c)触发了这20M日志对应的dirty pages强制写盘(监控表明约12000个page被刷盘)。 处于刷盘量峰值的17:05:14采集的innodb status数据显示存在大量锁等待的query,而前后10秒的innodb status中几乎没有等待的query,即刷盘操作对请求处理有较大影响。 所以在这个数据库中,增长innodb log file size,则可以保存更多的log,容忍更多的dirty page在buffer pool中,能减少由于log写满触发的脏页刷盘情况。 由此可见,innodb buffer pool中的脏页不仅仅只是由innodb_max_dirty_pages_pct来控制脏页对于整个buffer pool的最大比例, innodb_log_file_size*innodb_log_files_in_group得到的日志空间大小也能控制dirty page的总量。当然日志大小和数据大小没有一个绝对的比例,这个会由日志记录的更新内容的不同而不同。 mysql手册上说明了innodb的日志空间(innodb_log_file_size*innodb_log_files_in_group)可以设置为1M至整个innodb buffer pool的大小。 日志空间大的优点是,checkpoint触发数据flush的几率小,能容忍更多的脏页,有更多的机会进行脏页的merge,最终达到平滑IO,节省IO的目的。 日志空间大的缺点是:意味着innodb关闭或在crash后的恢复时间会非常慢。 出现异常的数据库拥有4G innodb buffer pool,但只设置了200M的日志空间,该值偏小是导致17点出现innodb大量物理写盘的一个主要原因。 5、总结 导致性能下降的根本原因是数据库的innodb_log_file_size 设置过小导致。

[该问题的解决方案] 推动业务修改定时任务脚本,通过分解大操作量的语句或其他方式,平滑数据库写入速度,减小数据库突发写入量。 调整数据库innodb_log_file_size,设置为一个更大的值,保证不要出现由于日志空间的overflow导致的脏页刷盘。

完成以上调整后,该数据库集群的性能陡降问题完全消失。

Innodb刷脏页技术深度挖掘的更多相关文章

  1. Mysql的刷脏页问题

    平时的工作中,不知道你有没有遇到过这样的场景,一条 SQL 语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢,并且这样的场景很难复现,它不只随机,而且持续时间还很短. 当内存数据 ...

  2. 【MySQL 读书笔记】SQL 刷脏页可能造成数据库抖动

    开始今天读书笔记之前我觉得需要回顾一下当我们在更新一条数据的时候做了什么. 因为 WAL 技术的存在,所以当我们执行一条更新语句的时候是先写日志,后写磁盘的.当我们在内存中写入了 redolog 之后 ...

  3. MySQL:刷脏页

    1. 脏页,干净页 当内存数据页和磁盘数据页上的内容不一致时,我们称这个内存页为脏页: 内存数据写入磁盘后,内存页上的数据和磁盘页上的数据就一致了,我们称这个内存页为干净页. 2. 刷脏页的时机 2. ...

  4. InnoDB Redo Flush及脏页刷新机制深入分析

    概要: 我们知道InnoDB采用Write Ahead Log策略来防止宕机数据丢失,即事务提交时,先写重做日志,再修改内存数据页,这样就产生了脏页.既然有重做日志保证数据持久性,查询时也可以直接从缓 ...

  5. MySQL中InnoDB脏页刷新机制Checkpoint

    我们知道InnoDB采用Write Ahead Log策略来防止宕机数据丢失,即事务提交时,先写重做日志,再修改内存数据页,这样就产生了脏页.既然有重做日志保证数据持久性,查询时也可以直接从缓冲池页中 ...

  6. 面试题:了解MySQL的Flush-List吗?顺便说一下脏页的落盘机制!(文末送书)

    Hi,大家好!我是白日梦! 今天我要跟你分享的MySQL话题是:"了解Flush-List吗?顺便说一下脏页的落盘机制!(文末送书)" 本文是MySQL专题的第 8 篇,共110篇 ...

  7. redis存在大量脏页问题的追查记录

    from:https://www.zybuluo.com/SailorXiao/note/136014 case现场 线上发现一台机器内存负载很重,top后发现一个redis进程占了大量的内存,TOP ...

  8. 8Manage:物流CRM,深度挖掘快递企业下一站蓝海!

    [导读]网购的普及加快了快递物流服务在中国的发展,而物流行业也开始展露出自身巨大的发展潜力和进步空间.其中,作为物流行业根本核心的物流客户关系管理开始引起了管理者的注意,如何升级用户物流服务体验,把握 ...

  9. Checkpoint--查看各DB上的脏页

    可以使用sys.dm_os_buffer_descriptors来看数据页在buffer pool中的状态,其中is_modified来标示数据页是否为脏页 --------------------- ...

随机推荐

  1. 数组 寻找最大的第k个数

    int Partion(int asy[],int begin,int end) { int k=begin; int key=asy[end]; for(int i=begin;i<=end; ...

  2. jquery.pagination.js分页插件的使用

    Pagination的相关参数: Pagination使用的核心代码:         //回调函数         function pageselectCallback(page_index, j ...

  3. sql 存储过程 循环使用

    USE [clab] GO /****** Object: StoredProcedure [dbo].[sp_bd_getResultByEcd] Script Date: 08/06/2014 1 ...

  4. 字符设备 register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()

    1. 字符设备结构体 内核中所有已分配的字符设备编号都记录在一个名为 chrdevs 散列表里.该散列表中的每一个元素是一个 char_device_struct 结构,它的定义如下: static ...

  5. windows/ubuntu 文件共享之 Samba 配置

    很多时候需要在windows上和ubuntu 上共享文件,一直没怎么去找方法,得知Samba 可以实现在windows上访问linux的文件,这样一来要从windows文件放到linux中就方便了,听 ...

  6. 删除 GPT 保护分区

    问题: 将内置和/或外置硬盘连接到 Windows XP 32 位操作系统时,将无法访问硬盘,“磁盘管理”将会报告该硬盘包含 GPT 保护分区.在此状态下,将无法对硬盘进行重新分区和格式化. 原因: ...

  7. C++中关于指针初始化和使用NULL的理解

    1.严禁使用未被初始化的指针:C++创建指针的时候,只分配存储地址的内存,并不会分配存储数据的内存,所以指针可能指向任何位置. (1)使用解除运算符(*)之前,一定要对指针初始化,否则若声明的指针刚好 ...

  8. devDependencies和dependencies的区别

    我们在使用npm install 安装模块或插件的时候,有两种命令把他们写入到 package.json 文件里面去,比如: --save-dev --save 在 package.json 文件里面 ...

  9. [LeetCode#247] Strobogrammatic Number II

    Problem: A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked a ...

  10. EXT 数据按F12,F11 显示问题

    最近做关于EXT的项目,因为是刚开始接触EXT,对什么都不熟悉,所以把其他人写好的浏览页代码考过了来,换成自己需要的. 一切都做好了,然后数据不出来,就调试看,后台也出现数据了,然后就按F12调试前台 ...