成为MySQL DBA博客-性能配置调优

导读

译者:田帅萌(邮箱:[email protected],欢迎交流

知数堂MySQL DBA班第9期优秀学员,Python运维开发班第5期学员,现任职知数堂助教

原文作者:Severalnines

原文出处:https://severalnines.com/blog/become-mysql-dba-blog-series-configuration-tuning-performance

一、简介

数据库服务器需要CPU、内存、 磁盘和网络才能运行,了解这些资源对于DBA来说非常重要,因为任何的超载行为都可能成为限制因素,导致数据库服务器性能不佳。DBA的主要任务就是调整系统和数据库的配置,避免可用资源的过渡利用和利用不足。

首先,性能优化是一个持续的过程,安装MySQL通常是调整操作系统和数据库配置的第一步。而数据库是一个动态系统,这是一个永无止境的故事。你的MySQL数据库起初可能是CPU绑定的,因为你有足够的内存和很少的数据。随着时间地推移,它可能会改变,磁盘访问可能会变得更加频繁。正如你可以想象的那样,I / O是主要关心的服务器配置,看起来不同于所有数据都适合内存的服务器的配置。此外,您的查询组合也可能随时间而改变,因此访问模式或MySQL中可用功能的使用(如自适应哈希索引)也会随之改变。

二、OS系统优化

需要检查内存和文件系统缓存处理方式相关的操作系统设置。一般来说,我们希望保持 vm.dirty_ratiovm.dirty_background_ratio都为低。

vm.dirty_background_ratio 是系统内存的百分比,在后台刷新过程开始之前,可以用来缓存已修改的(“脏”)页面,意味着需要做更多的工作来清理缓存。

另一方面,vm.dirty_ratio是可用于缓存脏页面的内存的硬限制。如果由于写入活动较高,后台进程无法快速刷新数据以跟上新的修改,则可以达到该目的。一旦达到vm.dirty_ratio,所有的I/O活动都被锁定,直到脏页被写入磁盘,这里的默认设置通常是40%(在你的发行版中可能会有所不同,但对于大容量内存的主机来说这个数字是相当高的)。假设对于一个128GB的实例,即使您使用的是快速固态硬盘,它也相当于51GB,这可能会在相当长的时间内锁定您的I/O。

一般来说,我们希望看到这两个变量设置为低的数值:5 - 10%。

另一个重要的系统变量是vm.swappiness。一方面,在使用MySQL的时候,我们不想使用交换,除非是急需,将InnoDB缓冲池交换到磁盘将删除内存缓冲池; 另一方面,如果替代方法是启动OOM并杀死MySQL,那我们宁愿不这样做。 这样的行为可以通过将vm.swappiness设置为0来实现。 因此, 如果它是保持MySQL的唯一选项,建议将vm.swappiness设置为1,以允许一些交换发生。当然,这会减慢系统,但MySQL上的OOM非常苛刻。

#注释:个人建议还是设置为 5-10左右

另一个与内存相关的设置,确保你将NUMA全部设置为关闭。你可以通过修改启动脚本来启动MySQL: numactl --interleave=all $command ,此设置可以平衡NUMA节点之间的内存分配,并最大限度地减少其中一个节点内存不足的机会。

内存分配器也可以对MySQL性能产生重大影响。你可以选择不同的内存分配器来使用MySQL。它们的性能在版本和工作负载之间有所不同,因此只有在执行了详细地测试后,才能确定在你的环境中哪个版本效果最好。最常见的选择是默认的glibc malloctcmallocjemalloc

你可以通过安装一个新的包(用于jemalloctcmalloc)来添加新的分配器,然后在[mysqld_safe]中使用LD_PRELOAD(即导出LD_PRELOAD =“/ usr / lib / libtcmalloc_minimal.so.4.1.2”)或malloc-lib变量部分my.cnf

接下来,你会想看看磁盘调度器。CFQ(通常是默认的CFQ)针对桌面工作负载进行了调整。这对于数据库工作负载来说效果不佳。大多数情况下,如果将其更改为noop或截止日期,会看到更好的结果。这两个调度器之间几乎没有什么区别,我们发现基于SAN的存储Noop略胜一筹(SAN通常在处理工作负载方面更好,因为它知道更多关于底层硬件以及与操作系统相比实际存储在缓存中的内容)。

现在我们正式谈论磁盘,通常文件系统的最佳选择是EXT4或XFS (过去这已经改变了几次),如果您想要充分利用I / O子系统,那么你可能必须对设置进行一些测试。无论使用哪种文件系统,都应该禁用MySQL卷的noatimenodiratime (对元数据的写入越少,整体开销就越低)。

三、MySQL配置调整

调整MySQL配置是整本书的一个主题,无法在一篇博客文章中将其覆盖。我们将尝试在这里提到一些更重要的变量。

InnoDB缓冲池

什么是缓冲池,为什么如此重要?缓冲池是InnoDB用来缓存数据的内存。它用于缓存读取和写入每个已经被修改的页面,首先必须加载到缓冲池,然后它变成了一个脏页面,即一个已经被修改的页面,并且还没有被刷新到表空间。正如你可以想象的,这样的缓冲区对于数据库正确执行非常重要。“内存/磁盘”比率越差,你的工作负载将越受限于I / O,I / O约束的工作量往往是缓慢的。

您可能已经听说过将InnoDB缓冲池设置为系统总内存的80%的经验法则。当8GB的内存是巨大的时候,它是有效的,但现在不是这样。在计算InnoDB缓冲池大小时,需要考虑其余MySQL的内存要求(假设MySQL是服务器上唯一运行的应用程序)。例如,我们在这里谈论每个连接,甚至每个查询缓冲区,如连接缓冲区或内存中临时表的最大区间,同时你还需要考虑允许的最大连接数(更多的连接意味着更多的内存使用量)。

对于具有24到32个内核和128GB内存的MySQL数据库服务器,处理多达20 - 30个同时运行的连接和多达数百个同时连接的客户端,我们可以说10 - 15GB的内存应该足够了。如果你想保持安全的话,20GB应该是足够的。一般来说,除非您知道数据库的行为,否则建立理想的缓冲池大小是一个反复试验的过程。在编写的时候,InnoDB缓冲池不是一个动态变量,所以需要重新启动。因此,在“太小”方面犯错是比较安全的。随着Oracle引入动态分配的缓冲池,它将随着MySQL 5.7而改变,这将使调整更容易。

MySQL使用比InnoDB缓冲池等多个缓冲区,它们是由变量控制:join_buffer_sizesort_buffer_size的值,read_buffer_sizeread_rnd_buffer_size。这些缓冲区是按会话分配的(连接缓冲区除外,每个JOIN分配一个缓冲区)。我们已经看到MySQL将这些缓冲区设置为数百兆字节 —通过增加join_buffer_size,你会期望JOIN执行得更快,更自然。

默认情况下,这些变量具有相当小的值,这实际上是有意义的 —我们已经看到,低至256K的设置可能比像4M这样的较大值快得多。很难说出这种行为的确切原因,很可能其中有很多。可以肯定的是,Linux改变了内存分配的方式。最多256KB使用malloc()。对于更大的内存块 - mmap(),重要的是要记住,当涉及到这些变量时,任何变化都必须以基准为后盾,以确认新的设置确实是正确的。否则,你可能会降低它的表现,而不是增加它。

InnoDB持久化

另一个对MySQL性能有重大影响的变量是innodb_flush_log_at_trx_commit,这是InnoDB持久性的延伸。默认:

(1)确保数据是安全的,即使数据库服务器被杀死 - 在任何情况下都不会丢失数据。其他设置(2和0)表示,整个数据库服务器可能会崩溃;

(2)则可能会丢失多达1个事务,并且如果mysqld被终止,则可能会丢失多达1个事务。

完全地持久性显然是一件好事,但它的价格非常高 - I / O负载要高得多,因为在每次提交之后,刷新操作必须发生。因此,在某些情况下,降低耐用性和在某些条件下承担数据丢失的风险是非常受欢迎的。对于主 - 多个从属设置来说,这是真实的,通常情况下,在重建过程中有一个从属在崩溃之后通常是完全正确的,因为其余部分可以轻松处理工作量。Galera群集也是如此: 整个群集作为单个实例工作,即使一个节点崩溃并丢失数据。

I / O相关的设置

其他可能对某些工作负载有重大影响的变量是innodb_io_capacityinnodb_io_capacity_maxinnodb_lru_scan_depth。这些变量定义了InnoDB的后台线程可以完成的磁盘操作的数量,例如,从InnoDB缓冲池中刷新脏页面。默认设置是保守的,大多数情况下都是好的。如果您的工作量非常大,您可能需要调整这些设置,看看您是不是阻止InnoDB完全使用您的I / O子系统。如果您拥有快速存储,则尤其如此:SSD或PCIe SSD卡。

说到磁盘,innodb_flush_method是另一个你可能想要看的设置。通过将此设置从默认的fdatasync切换到O_DIRECT,我们看到了可见的性能提升。这种增益在使用BBU备份的硬件RAID控制器的设置中清晰可见。另一方面,当涉及到EBS卷时,我们已经使用`O_DSYNC看到了更好的结果。在这里进行标记对于了解在特定情况下哪种设置更好是非常重要的。

InnoDB重做日志

InnoDB的重做日志的大小也是你可能想要看的东西。它由innodb_log_file_sizeinnodb_log_files_in_group管理。默认情况下,我们在一个组中有两个日志,每个大小约为50MB。这些日志用于存储写入事务,并按顺序写入。这里的主要问题是,MySQL不能在日志中用完空间,并且如果日志几乎已满,则必须停止整个活动并专注于将数据刷新到表空间。当然,这对应用程序来说是非常糟糕的,因为在这段时间内没有写入操作。这是我们上面讨论的InnoDB I / O设置非常重要的原因之一。我们也可以通过改变innodb_log_file_size来增加重做日志的大小。经验法则是将它们设置得足够大,以覆盖至少1小时的写入。

查询缓存

MySQL查询缓存也经常被“调整” 这个缓存存储SELECT语句的散列及其结果。有两个问题 :第一个问题是,缓存可能会频繁刷新,如果对给定的表执行任何DML,则将从查询缓存中删除与此表相关的所有结果,这严重影响了MySQL查询缓存的实用性。第二个问题是查询缓存受互斥体保护,访问被序列化。对于任何具有较高并发性的工作负载来说,这是一个重大的缺点和限制。因此强烈建议通过完全禁用MySQL查询缓存来“调整”MySQL缓存。你可以通过设置`query_cache_type来完成关闭。确实,在某些情况下,它可能有一些用处,但大多数情况下并非如此。而不是依靠MySQL查询缓存,您还可以利用任何其他外部系统(如Memcached或Redis)来缓存数据。

内部争用处理

您可能要查看的另一组设置是控制MySQL应创建的给定结构的多少个实例/分区的变量。我们在这里讨论变量:innodb_buffer_pool_instancestable_open_cache_instancesmetadata_locks_hash_instancesinnodb_adaptive_hash_index_partitions。这些选项清楚表明,例如,单个缓冲池或单个自适应散列索引可成为具有高并发性的工作负载的争用点时引入的。一旦你发现其中一个结构成为一个痛点(我们讨论了如何在早期的博客文章中捕捉到这些情况)你会想调整变量,但不幸的是,这里没有经验法则。建议单个缓冲池实例的大小至少应为2GB,因此对于较小的缓冲池,你可能需要坚持这个限制。在其他变量的情况下,如果我们讨论的是争用问题,那么你可能会增加这些数据结构的实例/分区的数量,但是没有关于如何实现的规则,因此您需要观察工作量并决定此时争用不再是问题。

其他设置

还有一些其他设置可能需要考虑,有些可以在设置时以最有效的方式应用,有些可以动态更改。这些设置不会对性能产生重大影响(有时影响也可能是负面影响),但记住它们仍然很重要。

max_connections: 一方面你想保持足够高以处理任何传入的连接;另一方面,由于大多数服务器无法同时处理数百个或更多的连接,因此您又不希望太高。解决此问题的一种方法是在应用程序端实现连接池,或者使用像HAProxy这样的负载平衡器来限制负载。

log_bin 如果您正在使用MySQL复制,则需要启用二进制日志。即使您不使用它们,保留它们也是非常方便的,因为它们可以用来进行时间点恢复。

#个人强烈建议注释使用row格式

skip_name_resolve 此变量决定是否在作为传入连接源的主机上执行DNS查找。如果启用,FQDN可作为主机在MySQL授权中使用。如果不是,只有用IP地址定义的用户才能工作。启用DNS查找的问题是,它可能会引入额外的延迟。DNS服务器也可以停止响应(因为崩溃或网络问题),在这种情况下,MySQL将不能接受任何新的连接。

innodb_file_per_table 这个变量决定InnoDB表是在单独的表空间(设置为1)还是在共享表空间(设置为0)时创建。当每个InnoDB表都有一个单独的表空间时,管理MySQL会容易得多。例如,对于单独的表空间,可以通过删除表或分区来轻松回收磁盘空间。共享表空间不起作用 - 回收磁盘空间的唯一方法是转储数据,清理MySQL数据目录,然后重新加载数据。显然,这并不方便。

现在就是这样。正如我们在开始时所提到的那样,调整这些设置可能不会使MySQL数据库的速度变得更快 。但通过调整查询,您有可能加快这一速度。但是他们对整体表现仍然有明显的影响。祝你好运,调整工作!

你可能感兴趣的:(成为MySQL DBA博客-性能配置调优)