MySQL高负载优化

占用CPU过高,可以做如下考虑:

1)一般来讲,排除高并发的因素,还是要找到导致你CPU过高的哪几条在执行的SQL,show processlist语句,查找负荷最重的SQL语句,优化该SQL,比如适当建立某字段的索引;

2)打开慢查询日志,将那些执行时间过长且占用资源过多的SQL拿来进行explain分析,导致CPU过高,多数是GroupBy、OrderBy排序问题所导致,然后慢慢进行优化改进。比如优化insert语句、优化group by语句、优化order by语句、优化join语句等等;

3)考虑定时优化文件及索引;

4)定期分析表,使用optimize table;

5)优化数据库对象;

6)考虑是否是锁问题;

7)调整一些MySQL Server参数,比如key_buffer_size、table_cache、innodb_buffer_pool_size、innodb_log_file_size等等;

8)如果数据量过大,可以考虑使用MySQL集群或者搭建高可用环境。

9)可能由于内存latch(泄露)导致数据库CPU高

10)在多用户高并发的情况下,任何系统都会hold不住的,所以,使用缓存是必须的,使用memcached或者redis缓存都可以;

11)看看tmp_table_size大小是否偏小,如果允许,适当的增大一点;

12)如果max_heap_table_size配置的过小,增大一点;

13)mysql的sql语句睡眠连接超时时间设置问题(wait_timeout)

14)使用show processlist查看mysql连接数,看看是否超过了mysql设置的连接数

配置优化

1使用 InnoDB 存储引擎

如果你还在使用 MyISAM 存储引擎,那么是时候转换到 InnoDB 了。有很多的理由都表明 InnoDB 比 MyISAM 更有优势,如果你关注性能,那么,我们来看一下它们是如何利用物理内存的:

  1. MyISAM:仅在内存中保存索引。
  2. InnoDB:在内存中保存索引和数据。

结论:保存在内存的内容访问速度要比磁盘上的更快。

下面是如何在你的表上去转换存储引擎的命令:

ALTER TABLE table_name ENGINE=InnoDB;

注意:你已经创建了所有合适的索引,对吗?为了更好的性能,创建索引永远是第一优先考虑的事情。

2 InnoDB 使用所有的内存

你可以在 my.cnf 文件中编辑你的 MySQL 配置。使用 innodb_buffer_pool_size 参数去配置在你的服务器上允许 InnoDB 使用物理内存数量。

对此(假设你的服务器仅仅运行 MySQL),公认的“经验法则”是设置为你的服务器物理内存的 80%。在保证操作系统不使用交换分区而正常运行所需要的足够内存之后 ,尽可能多地为 MySQL 分配物理内存。

因此,如果你的服务器物理内存是 32 GB,可以将那个参数设置为多达 25 GB。

innodb_buffer_pool_size = 25600M 

*注意:(1)如果你的服务器内存较小并且小于 1 GB。为了适用本文的方法,你应该去升级你的服务器。 (2) 如果你的服务器内存特别大,比如,它有 200 GB,那么,根据一般常识,你也没有必要为操作系统保留多达 40 GB 的内存。 *

3 InnoDB 多任务运行

如果服务器上的参数 innodb_buffer_pool_size 的配置是大于 1 GB,将根据参数 innodb_buffer_pool_instances 的设置, 将 InnoDB 的缓冲池划分为多个。

拥有多于一个的缓冲池的好处有:

在多线程同时访问缓冲池时可能会遇到瓶颈。你可以通过启用多缓冲池来最小化这种争用情况:

对于缓冲池数量的官方建议是:

为了实现最佳的效果,要综合考虑 innodb_buffer_pool_instancesinnodb_buffer_pool_size 的设置,以确保每个实例至少有不小于 1 GB 的缓冲池。

因此,在我们的示例中,将参数 innodb_buffer_pool_size 设置为 25 GB 的拥有 32 GB 物理内存的服务器上。一个合适的设置为 25600M / 24 = 1.06 GB

innodb_buffer_pool_instances = 24

连接超时

mysql> show variables like 'wait_timeout'; 睡眠连接超时秒数
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 120   |
+---------------+-------+
1 row in set (0.23 sec)

连接数

mysql> show variables like '%max_connections%'; mysql的最大连接数
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 6000  |
+-----------------+-------+
1 row in set (0.25 sec)
mysql> show global status like 'Max_used_connections'; 服务器响应的最大连接数3
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| Max_used_connections | 45    |
+----------------------+-------+
1 row in set (0.24 sec)

mysql服务器最大连接数值的设置范围比较理想的是:服务器响应的最大连接数值占服务器上限连接数值的比例值在10%以上,如果在10%以下,说明mysql服务器最大连接上限值设置过高.

Max_used_connections / max_connections * 100% = 45/6000 *100% =0.0075

增加max_connections参数的值,不会占用太多系统资源。系统资源(CPU、内存)的占用主要取决于查询的密度、效率等

临时表

mysql>  show global status like 'created_tmp%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 21755 |
| Created_tmp_files       | 94    |
| Created_tmp_tables      | 56250 |
+-------------------------+-------+
3 rows in set (0.09 sec)

每次创建临时表时,Created_tmp_table都会增加,如果磁盘上创建临时表,Created_tmp_disk_tables也会增加。Created_tmp_files表示MySQL服务创建的临时文件数,比较理想的配置是:

Created_tmp_disk_tables / Created_tmp_files *100% <= 25%

服务器Created_tmp_disk_tables / Created_tmp_files *100% =23%

打开表的情况

Open_tables表示打开表的数量,Opened_tables表示打开过的表数量,我们可以用如下命令查看其具体情况:

mysql> show global status like 'open%tables%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_tables   | 1994  |
| Opened_tables | 5132  |
+---------------+-------+
2 rows in set (0.23 sec)
如果Opened_tables数量过大,说明配置中table_open_cache的值可能太小
mysql> show variables like 'table_open_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| table_open_cache | 2000  |
+------------------+-------+
1 row in set (0.12 sec)

比较合适的值为:

open_tables / opened_tables* 100% > = 85%

1994 / 5132 *100% =38%

open_tables / table_open_cache* 100% < = 95%

1994 / 2000 *100% =99.7%

进程使用情况

MySQL服务器的配置文件中设置了thread_cache_size,当客户端断开时,服务器处理此客户请求的线程将会缓存起来以响应一下客户而不是销毁(前提是缓存数未达上线)Thread_created表示创建过的线程数,我们可以用如下命令查看:

mysql>  show global status like 'thread%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_cached    | 28    |
| Threads_connected | 17    |
| Threads_created   | 45    |
| Threads_running   | 3     |
+-------------------+-------+
4 rows in set (0.28 sec)
Threads_created的值过大的话,表明MySQL服务器一直在创建线程,这也是比较耗费资源的,可以适当增大配置文件中thread_cache_size的值。查询服务器thread_cache_size配置如下:
mysql> show variables like 'thread_cache_size';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| thread_cache_size | 68    |
+-------------------+-------+
1 row in set (0.31 sec)

查询缓存

query_cache_size是设置MySQL的Query Cache大小,query_cache_type是设置使用查询缓存的类型,我们可以用如下命令查看其具体情况:

mysql> show global status like 'qcache%';
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| Qcache_free_blocks      | 1       |
| Qcache_free_memory      | 1031832 |
| Qcache_hits             | 0       |
| Qcache_inserts          | 0       |
| Qcache_lowmem_prunes    | 0       |
| Qcache_not_cached       | 2181771 |
| Qcache_queries_in_cache | 0       |
| Qcache_total_blocks     | 1       |
+-------------------------+---------+
8 rows in set (0.29 sec)

MySQL查询缓存变量的相关解释如下:

Qcache_free_blocks: 缓存中相领内存快的个数。数目大说明可能有碎片。Flush query cache会对缓存中的碎片进行整理,从而得到一个空间块。

Qcache_free_memory:缓存中的空闲空间。

Qcache_hits:多少次命中。通过这个参数可以查看到Query Cache的基本效果。

Qcache_inserts:插入次数,没插入一次查询时就增加1。命中次数除以插入次数就是命中比率。

Qcache_lowmem_prunes:多少条Query因为内存不足而被清楚出Query Cache。通过Qcache_lowmem_prunes和Query_free_memory相互结合,能够更清楚地了解到系统中Query Cache的内存大小是否真的足够,是否非常频繁地出现因为内存不足而有Query被换出的情况。   

Qcache_not_cached:不适合进行缓存的查询数量,通常是由于这些查询不是select语句或用了now()之类的函数。

Qcache_queries_in_cache:当前缓存的查询和响应数量。

Qcache_total_blocks:缓存中块的数量。

我们在查询一下服务器上关于query_cache的配置:

mysql> show variables like 'query_cache%';
+------------------------------+---------+
| Variable_name                | Value   |
+------------------------------+---------+
| query_cache_limit            | 1048576 |
| query_cache_min_res_unit     | 4096    |
| query_cache_size             | 1048576 |
| query_cache_type             | OFF     |
| query_cache_wlock_invalidate | OFF     |
+------------------------------+---------+
5 rows in set (0.12 sec)

query_cache_limit:超过此大小的查询将不缓存。

query_cache_min_res_unit:缓存块的最小值。

query_cache_size:查询缓存大小。

query_cache_type:缓存类型,决定缓存什么样的查询,示例中表示不缓存select sql_no_cache查询。

query_cache_wlock_invalidat:表示当有其他客户端正在对MyISAM表进行写操作,读请求是要等WRITE LOCK释放资源后再查询还是允许直接从Query Cache中读取结果,默认为OFF(可以直接从Query Cache中取得结果。)

query_cache_min_res_unit的配置是一柄双刃剑,默认是4KB,设置值大对大数据查询有好处,但如果你的查询都是小数据查询,就容易造成内存碎片和浪费。

查询缓存碎片率 = Qcache_free_blocks /Qcache_total_blocks * 100%

如果查询碎片率超过20%,可以用 flush query cache 整理缓存碎片,或者试试减少query_cache_min_res_unit,如果你查询都是小数据库的话。

查询缓存利用率 = (Qcache_free_size –  Qcache_free_memory)/query_cache_size * 100%

查询缓存利用率在25%一下的话说明query_cache_size设置得过大,可适当减少;查询缓存利用率在80%以上而且Qcache_lowmem_prunes > 50的话则说明query_cache_size可能有点小,不然就是碎片太多。

查询命中率 (Qcache_hits - Qcache_insert)/Qcache)hits * 100%

示例服务器中的查询缓存碎片率等于20%左右,查询缓存利用率在50%,查询命中率在2%,说明命中率很差,可能写操作比较频繁,而且可能有些碎片。

排序使用情况

它表示系统中对数据进行排序时所用的Buffer,我们可以用如下命令查看:

mysql> show global status like 'sort%';
+-------------------+---------+
| Variable_name     | Value   |
+-------------------+---------+
| Sort_merge_passes | 37      |
| Sort_range        | 110404  |
| Sort_rows         | 1122189 |
| Sort_scan         | 795334  |
+-------------------+---------+
4 rows in set (0.26 sec)

Sort_merge_passes包括如下步骤:MySQL首先会尝试在内存中做排序,使用的内存大小由系统变量sort_buffer_size来决定,如果它不够大则把所有的记录都读在内存中,而MySQL则会把每次在内存中排序的结果存到临时文件中,等MySQL找到所有记录之后,再把临时文件中的记录做一次排序。这次再排序就会增加sort_merge_passes。实际上,MySQL会用另外一个临时文件来存储再次排序的结果,所以我们通常会看到sort_merge_passes增加的数值是建临时文件数的两倍。因为用到了临时文件,所以速度可能会比较慢,增大sort_buffer_size会减少sort_merge_passes和创建临时文件的次数,但盲目地增大sort_buffer_size并不一定能提高速度。

打开文件数(open_files)

我们现在处理MySQL故障时,发现当Open_files大于open_files_limit值时,MySQL数据库就会发生卡住的现象,导致Nginx服务器打不开相应页面。这个问题大家在工作中应注意,我们可以用如下命令查看其具体情况:

mysql> show global status like 'open_files';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_files    | 18    |
+---------------+-------+
1 row in set (0.30 sec)

比较合适的设置是:Open_files / Open_files_limit * 100% < = 75%

原文地址:https://www.cnblogs.com/FireLL/p/13794260.html