MySQL上线后根据status状态进行优化

MySQL数据库上线后,可以等其稳定运行一段时间后再根据服务器的status状态进行适当优化,我们可以用如下命令列出MySQL服务器运行的各种状态值:

mysql > show global status;

我个人比较喜欢的用法是 show status like '查询%';

1.慢查询

有时我们为了定位系统中效率比较低下的Query语法,需要打开慢查询日志,也就是Slow Que-ry log。打开慢查询日志的相关命令如下:

mysql> show variableslike '%slow%';

+---------------------+-----------------------------------------+

| Variable_name       |Value                                   |

+---------------------+-----------------------------------------+

| log_slow_queries    | ON                                     |

| slow_launch_time    | 2                                       |

+---------------------+-----------------------------------------+

 

mysql> show globalstatus like '%slow%';

+---------------------+-------+

| Variable_name       | Value|

+---------------------+-------+

| Slow_launch_threads | 0    |

| Slow_queries        | 2128   |

+---------------------+-------+

打开慢查询日志可能会对系统性能有一点点影响,如果你的MySQL是主从结构,可以考虑打开其中一台从服务器的慢查询日志,这样既可以监控慢查询,对系统性能影响也会很小。另外,可以用MySQL自带的命令mysqldumpslow进行查询。比如:下面的命令可以查出访问次数最多的20SQL语句:

mysqldumpslow-s c -t 20 host-slow.log

2.连接数

我们如果经常遇见MySQLERROR1040Too manyconnections的情况,一种情况是访问量确实很高,MySQL服务器扛不住了,这个时候就要考虑增加从服务器分散读压力。另外一种情况是MySQL配置文件中max_connections的值过小。来看一个例子。

mysql>show variables like'max_connections';

+-----------------+-------+

| Variable_name   | Value |

+-----------------+-------+

| max_connections | 800   |

+-----------------+-------+

这台服务器最大连接数是256,然后查询一下该服务器响应的最大连接数;

mysql> show global status like 'Max_used_connections';

+----------------------+-------+

| Variable_name        | Value|

+----------------------+-------+

| Max_used_connections | 245   |

+----------------------+-------+

MySQL服务器过去的最大连接数是245,没有达到服务器连接数的上线800,不会出现1040错误。

Max_used_connections/max_connections * 100% = 85%

最大连接数占上限连接数的85%左右,如果发现比例在10%以下,则说明MySQL服务器连接数的上限设置得过高了。

3.key_buffer_size

key_buffer_size是设置MyISAM表索引缓存空间的大小,此参数对MyISAM表性能影响最大。下面是一台MyISAM为主要存储引擎服务器的配置:

mysql> show variables like 'key_buffer_size';

+-----------------+-----------+

| Variable_name   | Value   |

+-----------------+-----------+

| key_buffer_size | 536870912 |

+-----------------+-----------+

从上面可以看出,分配了512MB内存给key_buffer_size。再来看key_buffer_size的使用情况:

mysql> show global status like 'key_read%';

+-------------------+--------------+

| Variable_name     | Value |

+-------------------+-------+

| Key_read_requests | 27813678766 |

| Key_reads          |  6798830      |

+-------------------+--------------+

一共有27813678766个索引读取请求,有6798830个请求在内存中没有找到,直接从硬盘读取索引。

key_cache_miss_rate = key_reads /key_read_requests * 100%

比如上面的数据,key_cache_miss_rate0.0244%4000%个索引读取请求才有一个直接读硬盘,效果已经很好了,key_cache_miss_rate0.1%以下都很好,如果key_cache_miss_rate0.01%以下的话,则说明key_buffer_size分配得过多,可以适当减少。

4.临时表

当执行语句时,关于已经被创建了隐含临时表的数量,我们可以用如下命令查询其具体情况:

mysql> show global status like 'created_tmp%';

+-------------------------+----------+

| Variable_name           |Value |

+-------------------------+----------+

| Created_tmp_disk_tables | 21119   |

| Created_tmp_files       |6     |

| Created_tmp_tables      |17715532  |

+-------------------------+----------+

每次创建临时表时,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% =1.20%,就相当不错。我们在看一下MySQL服务器对临时表的配置:

mysql> show variables where Variable_name in('tmp_table_size','max_heap_table_size');

+---------------------+---------+

| Variable_name       |Value   |

+---------------------+---------+

| max_heap_table_size | 2097152 |

| tmp_table_size      |2097152 |

+---------------------+---------+

5.打开表的情况

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

mysql> show global status like 'open%tables%';

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| Open_tables   | 351   |

| Opened_tables | 1455 |

如果Opened_tables数量过大,说明配置中table_open_cache的值可能太小。我们查询下服务器table_open_cache;

mysql> show variables like 'table_open_cache'; 

+------------------+-------+

| Variable_name    | Value |

+------------------+-------+

| table_open_cache | 2048  |

+------------------+-------+

比较合适的值为:

open_tables/ opened_tables* 100% > = 85%

open_tables/ table_open_cache* 100% < = 95%

6.进程使用情况

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

mysql> show global status like 'thread%';

+-------------------+-------+

| Variable_name     | Value |

+-------------------+-------+

| Threads_cached    | 40    |

| Threads_connected | 1     |

| Threads_created   | 330   |

| Threads_running   | 1     |

+-------------------+-------+

如果发现Threads_created的值过大的话,表明MySQL服务器一直在创建线程,这也是比较耗费资源的,可以适当增大配置文件中thread_cache_size的值。查询服务器thread_cache_size配置如下:

mysql> show variables like 'thread_cache_size';

+-------------------+-------+

| Variable_name     | Value |

+-------------------+-------+

| thread_cache_size | 100   |

+-------------------+-------+

示例中的MySQL服务器还是挺健康的。

7.查询缓存(querycache)

它主要涉及两个参数,query_cache_size是设置MySQLQuery Cache大小,query_cache_type是设置使用查询缓存的类型,我们可以用如下命令查看其具体情况:

mysql> show global status like 'qcache%';

+-------------------------+-----------+

| Variable_name           |Value  |

+-------------------------+-----------+

| Qcache_free_blocks      |22756     |

| Qcache_free_memory      |76764704  |

| Qcache_hits             | 213028692   |

| Qcache_inserts          |208894227   |

| Qcache_lowmem_prunes    |4010916    |

| Qcache_not_cached       |13385031    |

| Qcache_queries_in_cache | 43560    |

| Qcache_total_blocks     |111212    |

+-------------------------+-----------+

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_prunesQuery_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    | 2048    |

| query_cache_size            | 2097152 |

| query_cache_type            | ON      |

| query_cache_wlock_invalidate | OFF     |

+------------------------------+---------+

字段解释如下:

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

query_cache_min_res_unit缓存块的最小值。

query_cache_size查询缓存大小。

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

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

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

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

如果查询碎片率超过20%,可以用 flushquery 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%,说明命中率很差,可能写操作比较频繁,而且可能有些碎片。

8.排序使用情况

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

mysql> show global status like 'sort%';

+-------------------+----------+

| Variable_name     | Value |

+-------------------+----------+

| Sort_merge_passes | 10        |

| Sort_range        | 37431240   |

| Sort_rows         | 6738691532|

| Sort_scan         | 1823485     |

+-------------------+----------+

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并不一定能提高速度。

9.文件打开数(open_files)

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

show global status like 'open_files';

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| Open_files    | 1481   |

+---------------+-------+

mysql> show global status like 'open_files_limit';

+------------------+-------+

| Variable_name    | Value |

+------------------+--------+

| Open_files_limit | 4509 |

+------------------+--------+

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

10.InnoDB_buffer_pool_cache合理设置

InnoDB存储引擎的缓存机制和MyISAM的最大区别就在于,InnoDB不仅仅缓存索引,同时还会缓存实际的数据。此参数用来设置InnoDB最主要的Buffer的大小,也就是缓存用户表及索引数据的最主要缓存空间,对InnoDB整体性能影响也最大。

无论是MySQL官方手册还是网络上许多人分享的InnoDB优化建议,都是简单地建议将此值设置为整个系统物理内存的50%~80%。这种做法其实不妥,我们应根据实际的运行场景来正确设置此项参数。

MySQL优化小思想

很多时候我们会发现,通过参数设置进行性能优化所带来的性能提升,并不如许多人想象的那样会产生质的飞跃,除非是之前的设置存在严重不合理的情况。我们不能将性能调优完全依托与通过DBA在数据库上线后进行参数调整,而应该在系统设计和开发阶段就尽可能减少性能问题。(重点在于前期架构合理的设计及开发的程序合理)

MySQL数据库的可扩展架构方案

如果凭借MySQL的优化任无法顶住压力,这个时候我们就必须考虑MySQL的可扩展性架构了(有人称为MySQL集群)它有以下明显的优势:

  • 成本低,很容易通过价格低廉Pc server搭建出一个处理能力非常强大的计算机集群。

  • 不太容易遇到瓶颈,因为很容易通过添加主机来增加处理能力。

  • 单节点故障对系统的整体影响较小。

目前可行的方案如下:

1MySQL Cluter

其特点为可用性非常高,性能非常好。每份数据至少可在不同主机上存一份副本,且冗余数据拷贝实时同步。但它的维护非常复杂,存在部分Bug,目前还不适合比较核心的线上系统,所以暂时不推荐。

2DRBD磁盘网络镜像方案

其特点为软件功能强大,数据可在底层快设备级别跨物理主机镜像,且可根据性能可靠性要求配置不同级别的同步。I/O操作会保持顺序,可满足数据库对数据一致性的苛刻要求。但非分布式文件系统环境无法支持镜像数据同时可见,性能和可靠性两者互相矛盾,无法适用于性能和可靠性要求都比较苛刻的环境,维护成本高于MySQL Replication。另外,DRBD是官方推荐的可用于MySQL的搞可用方案之一,大家可根据实际环境来考虑是否部署。

3MySQL Replication

在工作中,此种MySQL搞可用、高扩展性架构也是用得最多的,我也推荐此方案,一主多从、双主多从是生产环境常见的高可用架构方案。

本文出自 “” 博客,请务必保留此出处