一个关于innodb_buffer_pool_size导致mysql重启的问题

jackxiang 2010-9-26 13:35 | |
最近一周游戏DB偶尔会出现异常重启的现象,观察日志发现
ersion: '5.*-log'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  Source distribution
080926 12:27:36  InnoDB: Error: cannot allocate 1064960 bytes of
InnoDB: memory with malloc! Total allocated memory
InnoDB: by InnoDB 1185388986 bytes. Operating system errno: 12
InnoDB: Check if you should increase the swap file or
InnoDB: ulimits of your operating system.
InnoDB: On FreeBSD check you have compiled the OS with
InnoDB: a big enough maximum process size.
InnoDB: Note that in most 32-bit computers the process
InnoDB: memory space is limited to 2 GB or 4 GB.
InnoDB: We keep retrying the allocation for 60 seconds...
080926 12:28:36  InnoDB: We now intentionally generate a seg fault so that
InnoDB: on Linux we get a stack trace.
mysqld got signal 11;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help diagnose
the problem, but since we have already crashed, something is definitely wrong
and this may fail.
key_buffer_size=402653184
read_buffer_size=2093056
max_used_connections=112
max_connections=200
threads_connected=90
It is possible that mysqld could use up to
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = 1211614 K
bytes of memory
Hope that's ok; if not, decrease some variables in the equation.
thd=(nil)
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
Cannot determine thread, fp=0x704a7e48, backtrace may not be correct.
Stack range sanity check OK, backtrace follows:
0x8174663
0xc72420
0x36392d39
0x8407481
0x83d085d
0x8318798
0xb512db
0xaab12e
New value of fp=(nil) failed sanity check, terminating stack trace!
Please read http://dev.mysql.com/doc/mysql/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved
stack trace is much more helpful in diagnosing the problem, so please do
resolve it
The manual page at http://www.mysql.com/doc/en/Crashing.html contains
information that should help you find out what is causing the crash.
Number of processes running now: 0

起初认为是key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections 的数值小于by InnoDB 1185388986 bytes的这个
经过和yc同学的探讨后决定把read_buffer_size+sort_buffer_size的值稍微上调,让合值超过2。
今早来后我们发现昨天的判断可能是错误的!
080926 12:27:36  InnoDB: Error: cannot allocate 1064960 bytes of
InnoDB: memory with malloc! Total allocated memory

innodb_buffer_pool_size的大小才是问题的关键 4G物理内存 手册来说建议把innodb_buffer_pool_size设定到物理内存的70%-80%也就是2.8-3.0G间
但是由于我们考虑到key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections +innodb_buffer_pool_size的因素,
最好商榷把innodb_buffer_pool_size=2.0G 这样mysql占用物理内存的极限总合控制在3.2G内

目前启动了!貌似看起来没有太大问题!.

How MySQL Uses Memory才是正解哈
http://dev.mysql.com/doc/refman/5.0/en/memory-use.html
http://imysql.cn/node/97

来源:http://zhangchunyang75252.spaces.live.com/Blog/cns!4C3483B296AD4DB!738.entry

究其原因:
MySQL Innodb里面的innodb_buffer_pool_size 参数
这个参数设置buffer_pool_size也就是缓冲池大小,官方的建议是不要超过2G。经过研究发现这个限制主要来自于如下原因:
32位的Linux内核,内存的寻址范围最大只能是4GB(2^32),这4GB当中0-3GB的给用户进程(User Space)使用,3-4GB给内核使用.也就是说像MySQL这样的进程分配的内存不能超过3GB,但是为什么 innodb_buffer_pool_size 设置成3GB不行呢?很简单,因为MySQL在分配这个内存的时候不仅仅是innodb_buffer_pool_size的设置值,还加了一个 struct:(innobase/ut/ut0mem.c)

81 ret = malloc(n + sizeof(ut_mem_block_t));

这样的话,设置成3GB后,malloc的结果会超过3GB,看到这种错误:

InnoDB: Error: cannot allocate 3221241856 bytes of

cat /proc/sys/vm/overcommit_memory  的输出是多少吗?
根据错误提示的内容,google一下,发现是内核限制的缘故:

[root@yejr mysql]# cat /proc/sys/vm/nr_hugepages
6000

修改一下内核限制:

[root@yejr mysql]# echo 0 > /proc/sys/vm/nr_hugepages


innodb_data_file_path 语法如下所示:

pathtodatafile:sizespecification;pathtodatafile:sizespec;...
...;pathtodatafile:sizespec[:autoextend[:max:sizespecification]]
autoextend参数,并表空间空间不够时,最后的一个文件将自动增长,并且每次自动增长8M.
为了保护文件系统,可以设置MAX参数限制其最后一个文件的最大大小。
在my.cnf参数文件中修改参数
innodb_data_file_path=ibdata1:100M;tbs_data_00:200M;tbs_data_01:200M:autoextend:max:2000M

重新启动数据库

mysqld_safe &

查看日志

080313 15:16:22  mysqld started
080313 15:16:23  InnoDB: Data file ./tbs_data_00 did not exist: new to be created
080313 15:16:23  InnoDB: Setting file ./tbs_data_00 size to 200 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Progress in MB: 100 200
080313 15:16:26  InnoDB: Data file ./tbs_data_01 did not exist: new to be created
080313 15:16:26  InnoDB: Setting file ./tbs_data_01 size to 200 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Progress in MB: 100 200
080313 15:16:32  InnoDB: Started; log sequence number 0 133856992
080313 15:16:32 [Note] /opt/coolstack/mysql_32bit/bin/mysqld: ready for connections.
Version: '5.0.45-standard'  socket: '/tmp/mysql.sock'  port: 3306  Source distribution


show variables like "%innodb%"


添加与移除 InnoDB 数据和日志文件:

为了添加一个数据文件到表空间中,首先要关闭 MySQL 数据库,编辑 my.cnf 文件,在 innodb_data_file_path 中添加一个新文件,然后再重新启动服务。

如果,最后一个文件以关键字 autoextend 来描述,那么编辑 my.cnf 的过程如下所示。必须检查最后一个文件的尺寸,并使它向下接近于 1024 * 1024 bytes (= 1 MB) 的倍数,并在 innodb_data_file_path 中明确指定它的尺寸。然后你可以添加另一个数据文件。记住只有 innodb_data_file_path 中的最后一个文件可以被指定为 auto-extending。

一个例子:假设起先仅仅只有一个 auto-extending 数据文件 ibdata1 ,这个文件越越接近于 988 MB。下面是添加了另一个 auto-extending 数据文件后的可能示例 。

innodb_data_home_dir =
innodb_data_file_path = /ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend

通常不能移除 InnoDB 的数据文件。为了减小数据文件的大小,你必须使用 mysqldump 来转储(dump)所有的数据表,再重新建立一个新的数据库,并将数据导入新的数据库中。

如果希望改变 InnoDB 的日志文件数目,必须先关闭 MySQL 并确定完全关闭而没有发生任何错误。将旧的日志文件复制到其它安全的地方,以防在关闭服务时发生了错误而需要恢复数据库。删除所有日志文件,编辑 my.cnf,再重新启动 MySQL。InnoDB 在启动时将会提示它在建立新的日志文件。

增加InnoDB表空间大小的方法是从开始配置它为自动扩展的。为表空间定义里的最后一个数据文件指定autoextend属性。然后在文件耗尽空间之时,InnoDB以8MB为 增量自动增加该文件的大小。增加的大小可以通过设置innodb_autoextend_increment值来配置,这个值以MB为单位,默认的是8。

作为替代,你可以通过添加另一个数据文件来增加表空间的尺寸。要这么做的话,你必须停止MySQL服务器,编辑my.cnf文件 ,添加一个新数据文件到innodb_data_file_path的末尾,然后再次启动服务器。

如果最后一个数据文件是用关键字autoextend定义的,编辑my.cnf文件的步骤必须考虑最后一个数据文件已经增长到多大。获取数据文件的尺寸,把它四舍五入到最接近乘积1024 × 1024bytes (= 1MB),然后在innodb_data_file_path中明确指定大致的尺寸。然后你可以添加另一个数据文件。记得只有innodb_data_file_path里最后一个数据可以被指定为自动扩展。

作为一个例子。假设表空间正好有一个自动扩展文件ibdata1:

innodb_data_home_dir =

innodb_data_file_path = /ibdata/ibdata1:10M:autoextend

假设这个数据文件过一段时间已经长到988MB。下面是添加另一个总扩展数据文件之后的配置行:

innodb_data_home_dir =

innodb_data_file_path = /ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend

当你添加一个新文件到表空间的之后,请确信它并不存在。当你重启服务器之时,InnoDB创建并初始化这个文件。

当前,你不能从表空间删除一个数据文件。要增加表空间的大小,使用如下步骤:

1.    使用mysqldump转储所有InnoDB表。

2.    停止服务器。

3.    删除所有已存在的表空间文件。

4.    配置新表空间。

5.    重启服务器。

6.    导入转储文件。

如果你想要改变你的InnoDB日志文件的数量和大小,你必须要停止MySQL服务器,并确信它被无错误地关闭。随后复制旧日志文件到 一个安全的地方以防万一某样东西在关闭时出错而你需要用它们来恢复表空间。从日志文件目录删除所有旧日志文件,编辑my.cnf来改变日志文件配置,并再 次启动MySQL服务器。mysqld在启动之时发现没有日志文件,然后告诉你它正在创建一个新的日志文件。

InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。InnoDB存储它的表&索引在一个表空间中,表空间可以包含数个文件(或原始磁盘分区)。这与MyISAM表不同,比如在MyISAM表中每个表被存在分离的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制为2GB的操作系统上。

InnoDB查起来比较慢,myisam较快了,MYISAM的读速度比INNODB的快!写比INNODB的慢!MYISAM的索引会采用前缀压缩,故索引比innodb要小得多(针对字符串列)。

Innodb 去掉事务 速度也不错  Innodb 去掉事务 速度也不错  Innodb 去掉事务 速度也不错  Innodb 去掉事务 速度也不错
继续参考:
http://imysql.cn/docs/innodb/1.htm  ---》http://imysql.cn/docs/innodb/6.htm

作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:http://jackxiang.com/post/3537/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!


最后编辑: jackxiang 编辑于2010-9-26 18:00
评论列表
发表评论

昵称

网址

电邮

打开HTML 打开UBB 打开表情 隐藏 记住我 [登入] [注册]