如果你正在运行一个以 MySQL 数据库为主的写操作密集型应用程序,你可能会注意到当服务器上的写负载增加时,性能会大幅度降低。在我们的案例中,我们运行的是一个基于 Laravel 的基于事件源的服务,它将传入的事件写入读取表中。在高负载写入下,简单的插入和更新操作(负载较小)的执行时间达到了 250ms。以下是加快这些慢速写入的方法。
使用高性能 SSD 存储作为服务器支持
MySQL(默认设置)在每次事务后将日志缓冲区写入磁盘。在高负载下,这会导致大量的小写入操作,这些操作在传统的硬盘驱动器上尤其缓慢。
在我们的案例中,我们低估了 Amazon RDS 实例的磁盘大小,这对写性能有直接影响(更高的容量意味着更多的配置 IOPS/写入带宽)。增加磁盘大小将写入的平均时间降低了约 50ms。
TL;DR:确保你服务器的磁盘尽可能快
增加日志文件大小限制
默认的 innodb_log_file_size
限制设置为仅为 128M
,这并不适合高插入负载的环境。将其增加到更大的值,如 500M
,可以减少日志刷新(日志刷新比较慢,因为你是在写入磁盘)。这对于插入大量数据尤其重要。
在我们的案例中,增加日志文件大小并没有真正帮助到我们,因为我们有大量的较小读取(不足以频繁地溢出日志文件)。
通过较少刷新日志来延迟磁盘写入
默认情况下,MySQL会在每次事务后都将日志写入磁盘。在我们的情况下,我们无法将插入批次包裹在事务中,因此每次插入查询都会导致磁盘写入。
您可以通过将innodb_flush_log_at_trx_commit
设置为2
,将日志写入磁盘的间隔改为定时。将此设置从默认的1
分开的主要问题是可能丢失数据。尽管您仍然受到MySQL崩溃导致数据丢失的保护,但整个服务器失去电力可能会导致潜在的数据丢失。例如,如果您的刷新间隔设置为默认的1
,服务器故障可能会导致一秒的写入丢失。
将innodb_flush_log_at_trx_commit
设置为2
,我们能够将插入时间平均从超过200毫秒降低到不到50毫秒。这是一个相当大的改进,但如果您愿意冒更多秒数的潜在数据丢失风险,可以进一步压缩速度。
您可以通过将innodb_flush_log_at_timeout
设置为所需的间隔(秒)来增加刷新间隔。在我们的案例中,我们选择了5秒,这导致插入时间平均下降到5毫秒以下!与原始的250毫秒相比,这是一个巨大的差异,并且在我们的情况下,值得冒5秒潜在数据丢失的风险。
driesvints, ssatz, chrisbjr, rufflesaurus, ostap 点赞了这篇文章