IO等待造成如此之多的减速(在99%IO的EXT4 JDB2)在Mysql提交期间

我正在写一个索引器,使用python,索引文件并将它们插入到数据库中。在它是单个进程之前,但是现在我使用4个并行进程进行多处理。每次文本提取之后,它将插入数据库并进行提交。

现在它遇到IO问题,主要IO问题不是我的过程,而是EXT4的jdb2,journeling系统。 在每个MySQL提交中,等待IO的时间为99.99%,并等待CPU。

我看到很多在互联网上有这个问题,他们的解决scheme是安装使用barrier = 0。 这将完全禁用日记? 我的服务器有UPS和诱惑去做,我应该吗?

在永续性和性能之间总会有一个折衷。

在ext4上使用MySQL时,barrier = 1的默认值确实会导致速度变慢,但是第一个操作不应该是禁用日志logging或打开data = writeback。

首先,如果弹性是非常重要的,那么电池支持RAID是非常值得的。

我select的安装选项,特别是在非电池支持的RAID上:

/dev/mapper/vg-mysql--data /var/lib/mysql/data ext4 defaults,noatime,nodiratime,barrier=1,data=ordered 0 0 

这是故意不使用数据=回写,因为我不想冒险的文件系统损坏导致“旧数据出现在崩溃和日志恢复后的文件”(引用是从man mount )。

my.cnf中有关I / O相关设置的完整弹性的理想configuration是:

 [mysqld] sync_binlog = 1 innodb_flush_log_at_trx_commit = 1 

为了提高性能,我select了以下一系列权衡:

  1. sync_binlog = 0 :这是第一个改变了完全弹性的MySQLconfiguration。 原因是它可以显着提高性能,尤其是在binlog_format=row (不幸的是Jira需要)的情况下。 我在集群中使用了足够的MySQL副本,如果binlog被损坏的情况下,我会做从另一个副本的二进制副本。
  2. innodb_flush_log_at_trx_commit = 2 :完全符合ACID要求值为1,值为2“时,日志缓冲区会在每次提交时写入文件,但不执行刷新到磁盘的操作,但是,在值为2时,每秒也会刷新日志文件。请注意,由于进程调度问题,每秒一次的刷新不是100%保证。 (来自MySQL文档的引用)
  3. 更新挂载选项以使用data=writeback 。 请注意,如果这是您的根文件系统,您还需要传递内核命令行选项。 我在coderwall上放了几个步骤。
  4. testinginnodb_flush_method各种值。 显示O_DIRECT可以提高某些工作负载的性能,但是这并不是一定能够在您的环境中工作的。
  5. 升级到固态硬盘,在这种情况下,您还需要增加innodb_io_capacity ,并调整诸如innodb_adaptive_flushinginnodb_read_io_threadsinnodb_write_io_threadsinnodb_purge_threads和其他可能的设置等设置。

将数据库放在非日志文件系统上。 至less较大的服务器(oracle,sql server)具有自己的日志function(事务日志),并相应地优化其IO。 在单独的文件系统和磁盘上有日志和数据库,并依靠数据库内部function来处理错误的IO。 通常没有(更大的设置)文件系统的变化,除了写date,因为文件不扩大 – 他们将被生成与他们的“最后”的大小(好吧,pipe理员可以改变这一点),和变化是我所说的数据库级别的事务日志。

你也可能想告诉我们你的硬件层是什么。 大多数人低估IOPS是数据库的限制因素,认为小型光盘集合适合大型数据库。 虽然我们中的一些人在使用大量光盘的数据库上工作,因此可能会支持更多的IOPS。

很有可能你的I / O后端不能很好地处理负载。 你应该确保你的文件系统不logging数据。 我build议使用data=writeback,relatime,nobarrier参数来装载数据库的数据分区,作为第一个快速和肮脏的优化。

此外,从你的症状中推断,你显然没有使用你的控制器写caching。 您应确保在控制器上使用电池备份或闪存支持的写入caching,并启用它 – 这应该会显着提升性能,而不会大大增加数据丢失或损坏的风险。 请注意,在没有电池或闪存备份的情况下使用写入caching确实会增加数据丢失或损坏的风险 – 所以只能用于testing目的和/或如果可以承受损失。

这是一个老问题,但是我们在一个新的专用服务器上面对同样的问题(高IO等待,可怕的插入/更新速度),这个解决scheme直接解决了这个问题。

使用tune2fs -O "^has_journal" /dev/<drive>禁用日志loggingtune2fs -O "^has_journal" /dev/<drive>是最快的解决scheme,因为它消除了由于JDB2进程造成的IO等待。 但是,除非您有电池备份驱动器,否则不build议这样做,因为在发生故障时会丢失数据。 InnoDB表是安全的,如果你在MySQL中启用了doublewrite 。 但是.frm,日志等文件是不安全的。 我们尝试将这些文件移动到另一个驱动器(特别是bin日志),但jdb2 IO等待仍然存在。 所以它没有让我们很舒服。

data=writeback,relatime,nobarrier并没有帮助它加速写入/读取和在整个分区上禁用日志logging一样多。 ext4的更多选项在EXT4文档中 。

在我们的情况下真正的罪魁祸首是sync_binlog 。 我们在/etc/mysql/my.cnf设置为1 ,这是在杀死性能。

Percona在此validation 。 我们将其设置为默认值0 ,性能提高了500%以上。

你用什么数据库引擎来插入这些数据?

如果是MyISAM:在写入时必须locking整个表,所以运行并发的插入线程将会杀死任何系统,不pipe它有多强大。

确保你使用InnoDB来处理这些表格。

另外,与mysql没有直接关系,但是由于电力pipe理的积极性,一些HD有ext4的问题…当这种情况发生时,机器负载增加而没有任何明显的活动。

尝试禁用它。 首先检查你有什么价值(如果你需要把它放回去,而不重新启动),然后禁用它。

检查当前值:

  hdparm -B /dev/sda 

禁用它

  hdparm -B 255 /dev/sda 

(或任何你的HD)和testing。 可能对大多数问题没有帮助,但可能会帮助一些用户。 重新启动将重置该值,或者手动replace之前值为255的值。

如果有帮助,通过在启动时设置它,检查/etc/default/hdparm/etc/hdparm.conf以获得更加永久的configuration。