首先 性能优化是一个持续的过程,安装MySQL通常是调整操作系统和数据库配置的第一步。而数据库是一个动态系统,这是一个永无止境的故事。你的MySQL数据库起初可能是CPU绑定的,因为你有足够的内存和很少的数据。随着时间的推移,它可能会改变,磁盘访问可能会变得更加频繁。正如你可以想象的那样,I / O是主要关心的服务器的配置看起来不同于所有数据都适合内存的服务器的配置。此外,您的查询组合也可能随时间而改变,因此访问模式或MySQL中可用功能的使用(如自适应哈希索引)可随之改变。
OS系统优化
需要检查内存和文件系统缓存处理方式相关的操作系统设置。一般来说,我们希望保持vm.dirty_ratio
和vm.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来实现。
因此,建议将vm.swappiness
设置为1,以允许一些交换发生,
如果它是保持MySQL的唯一选项。当然,这会减慢系统,但是MySQL上的OOM非常苛刻。
注释 个人建议还是设置为 5-10左右
另一个与内存相关的设置
确保您将NUMA
全部设置为关闭。你可以通过修改启动脚本启动MySQL来完成:numactl --interleave=all $command
此设置可以平衡NUMA节点之间的内存分配,并最大限度地减少其中一个节点内存不足的机会。
内存分配器也可以对MySQL性能产生重大影响。这是一个较大的话题,我们只是在这里表面。你可以选择不同的内存分配器来使用MySQL。它们的性能在版本和工作负载之间有所不同,因此只有在执行了详细的测试后,才能确定在您的环境中哪个版本效果最好。最常见的选择是默认的glibc malloc,tcmalloc和jemalloc。你可以通过安装一个新的包(用于jemalloc和tcmalloc)来添加新的分配器,然后在[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卷的noatime和nodiratime - 对元数据的写入越少,整体开销就越低。
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_size
,sort_buffer_size
的值,read_buffer_size
,read_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_capacity
,innodb_io_capacity_max
和innodb_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_size
和innodb_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_instances
,table_open_cache_instances
,metadata_locks_hash_instances
和innodb_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数据库的速度变得更快 - 通过调整查询,您更有可能加快这一速度。但是他们应该对整体表现仍然有明显的影响。祝你好运,调整工作!