注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭研后台技术中心的博客

 
 
 
 
 

日志

 
 

MySQL OOM 系列四 MySQL内存相关参数优化  

来自郭忆   2013-08-19 18:12:43|  分类: 默认分类 |举报 |字号 订阅

  下载LOFTER 我的照片书  |
     上一章节讲述了如何降低MySQL被kill的风险,其中很重要的一条就是合理的规划MySQL的内存使用,这也是一个“老大难”的问题,我们这章就来详细讨论一下这个问题。我们首先需要了解一下MySQL是如何使用内存的。MySQL使用的内存主要有2类,一类是共享内存,一类是连接私有内存。
  
共享内存相关参数:
   1)
innodb_buffer_pool_size:使用过Innodb的同学都知道,这块内存是Innodb存储引擎最重要的内存,直接关系到MySQL的读写性能。与Myisam表只缓存索引,数据寄望于OS系统缓存不同,Innodb一般都会关闭OS的缓存,所有读到数据页和索引都直接存在数据库层的innodb_buffer_pool中的,这与Innodb是事务存储引擎有关,所以这个值越大MySQL性能当然也越好,但是有个前提需要讲明白,innodb_buffer_pool越大,不仅预热慢,崩溃恢复的速度也会很慢。这个值一般在保证了其他用途的内存够用的前提下,应尽可能的大。我们来看一下AWS(亚马逊云计算)不同规格的RDS该参数的设置情况:

规格

内存

innodb_buffer_pool_size

比例

db.t1.micro

613M

311M

50%

db.m1.small

1.7G

1.1G

64%

db.m1.medium

3.75G

2.66G

70%

db.m1.large

7.5G

5.47G

72%

db.m1.xlarge

15G

11G

73%

db.m2.xlarge


17.1G

12G

70%

db.m2.2xlarge


34G

25G

73%

db.m2.4xlarge


68G

51G

75%

  之所以AWS的各种规格的内存这么零碎,我觉得可能AWS已经抛掉了一些它自己部署的一些程序持有的内存,所以这里就已经是MySQL实际能够使用的内存大小了,基本上规格越低,Innodb_buffer_pool_size的比例越小,这个主要是因为每个连接的私有内存是固定的,所以对于小规格的实例,本身内存就比较小,为了保证一定的并发连接数,所以Innodb_buffer_pool_size也相对较小,这个是合理的。我们目前RDS一刀切75%的Innodb_buffer_pool分配显然是不合理,应该按照实际内存大小,内存越小,比例越低的原则进行设定。
     2)innodb_additional_mem_pool_size:主要用于存放MySQL内部的数据结构和Innodb的数据字典,所以大小主要与表的数量有关,表越多值越大。庆幸的是这个值是可变的,如果不够用的话,MySQL会向操作系统申请的。该值默认8M,AWS所有规格都是统一的2M,由于这个值可以动态申请,所以我觉得2M应该是满足需求的。
     3)innodb_log_buffer_size:这个是redolog的缓冲区,为了提高性能,MySQL每次写日志都将日志先写到一个内存Buffer中,然后将Buffer按照innodb_flush_log_at_trx_commit的配置刷到disk上。目前,我们所有实例的innodb_flush_log_at_trx_commit设置为了1,即每次事务提交都会刷新Buffer到磁盘,保证已经提交的事务,redo是不会丢的。AWS该值也设的是1(为了保证不丢数据),这个值的大小主要影响到刷磁盘的次数,设置的过小,Buffer容易满,就会增加fsync的次数,设置过大,占用内存。该值默认是8M,AWS所有规格统一128M,我觉得目前每次提交都会刷buffer,所以除非有大事务的情况,一般buffer不太可能被占满,所以没必要开的很大, 8M应该是满足需求的。
     4)key_buffer_size:myisam表的键缓存,这个只对myisam存储引擎有效,所以对于我们绝大多数使用Innodb的应用,无需关心。
     5)query_cache_size:MySQL对于查询的结果会进行缓存来节省解析SQL、执行SQL的花销,query_cache是按照SQL语句的Hash值进行缓存的,同时SQL语句涉及的表发生更新,该缓存就会失效,所以这个缓存对于特定的读多更新少的库比较有用,对于绝大多数更新较多的库可能不是很适用,比较受限于应用场景,所以AWS也把这个缓存给关了。我觉得这个值默认应该关闭,根据需求调整。
     上面这些就是MySQL主要的共享内存空间,这些空间是在MySQL启动时就分配的,但是并不是立即使用的。MySQL还有一部分内存是在用户连接请求到达时动态分配的,即每个MySQL连接都单独一个缓存,这部分缓存主要包括:
     1)read_buffer_size & read_rnd_buffer_size这两个值主要针对的都是Myisam表引擎,用来加快随机和顺序扫描表,对于innodb表,虽然在排序的时候,可以缓存临时文件中的索引,缓存嵌套查询的结果等作用,但是重要性已经下降很多了。这两个值前者默认128K,AWS统一256K,我们采用默认值。后者默认256K,AWS统一512K,我们也采用默认值。
    2) sort_buffer_size:每一个要做排序的请求,都会分到一个sort_buffer_size大的缓存,用于做order by和group by的排序,如果设置的缓存大小无法满足需要,MySQL 会将数据写入磁盘来完成排序。因为磁盘操作和内存操作不在一个数量级,所以 sort_buffer_size 对排序的性能影响很大。由于这部分缓存是即使不用这么大,也会全部分配的,所以对系统内存分配开销是比较大的,如果是希望扩大的话,建议在会话层设置,默认值2M,AWS也是2M。
    3)thread_stack:默认256K,AWS256K,MySQL为每个线程分配的堆栈。
    4)join_buffer_size每个连接的每次join都分配一个,默认值128K,AWS 128K;
    5)binlog_cache_size类似于innodb_log_buffer_size缓存事务日志,binlog_cache_size缓存Binlog,不同的是这个是每个线程单独一个,主要对于大事务有较大性能提升。默认32K,AWS 32K
     6)tmp_table_size 默认16M,用户内存临时表的最大值,如果临时表超过该值,MySQL就会把临时表转换为一个磁盘上mysiam表。如果用户需要做一些大表的groupby的操作,可能需要较大的该值,由于是与连接相关的,同样建议在会话层设置。AWS 16M
     经过上面的分析,我们重新规划了RDS的内存相关的参数,并且设置oom_adj为-17,同时加强了线上库内存的监控,来防止OOM的再次发生。
  评论这张
 
阅读(1679)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017