当我增加 max_heap_table_size 值时,MySQL 崩溃

当我增加 max_heap_table_size 值时,MySQL 崩溃

我在一台配备 120 GB RAM 的 Ubuntu 12.04 服务器上运行了一个 MySQL 实例。它上面运行着几个 PHP 脚本,有时会设置新的 mysql 参数。其中一个脚本使用大型 MEMORY 表来合并数据,然后再将其插入 MySISAM 表。

最近我将 max_heap_table_size 和 tmp_table_size 从 16 GB 更新为 20 GB,以避免出现“表已满”错误。结果,MySQL 在脚本的下一次运行中崩溃了。

实际上它首先生成了一个 strack 跟踪:

14:30:19 UTC - 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=536870912
read_buffer_size=131072
max_used_connections=85
max_threads=700
thread_count=82
connection_count=81
It is possible that mysqld could use up to
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 2055554 K  bytes of memory
Hope that's ok; if not, decrease some variables in the equation.

Thread pointer: 0x7ff66dbb4f30
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...
stack_bottom = 7ff632b80e60 thread_stack 0x28000
/usr/sbin/mysqld(my_print_stacktrace+0x29)[0x7ff66b087589]
/usr/sbin/mysqld(handle_fatal_signal+0x483)[0x7ff66af4c9d3]
/lib/x86_64-linux-gnu/libpthread.so.0(+0xfcb0)[0x7ff669c96cb0]
/usr/sbin/mysqld(_Z10field_convP5FieldS0_+0x37)[0x7ff66af49077]
/usr/sbin/mysqld(_ZN10Item_field13save_in_fieldEP5Fieldb+0x46)[0x7ff66af599b6]
/usr/sbin/mysqld(_Z11fill_recordP3THDPP5FieldR4ListI4ItemEb+0x4e)[0x7ff66adf3afe]
/usr/sbin/mysqld(_ZN12select_union9send_dataER4ListI4ItemE+0x6f)[0x7ff66aea705f]
/usr/sbin/mysqld(+0x32c554)[0x7ff66ae5a554]
/usr/sbin/mysqld(+0x3225cf)[0x7ff66ae505cf]
/usr/sbin/mysqld(_Z10sub_selectP4JOINP13st_join_tableb+0x7e)[0x7ff66ae5255e]
/usr/sbin/mysqld(+0x335274)[0x7ff66ae63274]
/usr/sbin/mysqld(_ZN4JOIN4execEv+0xc03)[0x7ff66ae72ec3]
/usr/sbin/mysqld(_Z12mysql_selectP3THDPPP4ItemP10TABLE_LISTjR4ListIS1_ES2_jP8st_orderSB_S2_SB_yP13select_resultP18st_select_lex_unitP13st_select_lex+0x130)[0x7ff66ae6e610]
/usr/sbin/mysqld(_Z21mysql_derived_fillingP3THDP3LEXP10TABLE_LIST+0x121)[0x7ff66ae13671]
/usr/sbin/mysqld(_Z20mysql_handle_derivedP3LEXPFbP3THDS0_P10TABLE_LISTE+0x68)[0x7ff66ae130f8]
/usr/sbin/mysqld(_Z20open_and_lock_tablesP3THDP10TABLE_LISTbjP19Prelocking_strategy+0x11a)[0x7ff66adf7c9a]
/usr/sbin/mysqld(+0x2fac95)[0x7ff66ae28c95]
/usr/sbin/mysqld(_Z21mysql_execute_commandP3THD+0x16a6)[0x7ff66ae307f6]
/usr/sbin/mysqld(_Z11mysql_parseP3THDPcjP12Parser_state+0x10f)[0x7ff66ae35a0f]
/usr/sbin/mysqld(_Z16dispatch_command19enum_server_commandP3THDPcj+0x1e71)[0x7ff66ae37951]
/usr/sbin/mysqld(_Z24do_handle_one_connectionP3THD+0x1bd)[0x7ff66aeddd9d]
/usr/sbin/mysqld(handle_one_connection+0x50)[0x7ff66aedde00]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x7e9a)[0x7ff669c8ee9a]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7ff6693bf3fd]

Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (7fea98004a80): is an invalid pointer
Connection ID (thread ID): 15144
Status: NOT_KILLED

The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains
information that should help you find out what is causing the crash.

一小时后发生崩溃/重启:

131122 15:30:24 [Warning] Using unique option prefix myisam-recover instead of myisam-recover-options is deprecated and will be removed in a future release. Please use the full name instead.
131122 15:30:24 [Warning] Using unique option prefix myisam-recover instead of myisam-recover-options is deprecated and will be removed in a future release. Please use the full name instead.
131122 15:30:24 [Note] Plugin 'FEDERATED' is disabled.
131122 15:30:24 InnoDB: The InnoDB memory heap is disabled
131122 15:30:24 InnoDB: Mutexes and rw_locks use GCC atomic builtins
131122 15:30:24 InnoDB: Compressed tables use zlib 1.2.3.4
131122 15:30:24 InnoDB: Initializing buffer pool, size = 128.0M
131122 15:30:24 InnoDB: Completed initialization of buffer pool
131122 15:30:24 InnoDB: highest supported file format is Barracuda.
InnoDB: Log scan progressed past the checkpoint lsn 1319218667
131122 15:30:24  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.

不幸的是,我没有 binlog 或慢查询日志输出可以发布在这里,但我可以说的是,在生成堆栈跟踪后,PHP 脚本继续运行。它在 mysql 重启期间停止。

不应考虑硬件故障,因为此错误已经发生在两台不同的服务器上。

崩溃的原因可能是什么?如何才能找出可以使用的最大值 max_heap_table_size 和 tmp_table_size 而不会导致 mysql 崩溃?

ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 1031141
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1031141
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Ubuntu 12.04,1 的 mysql 版本是 5.5.34

答案1

有了 120GB 的内存,您的机器似乎也可能具有多个物理 CPU 和非统一内存访问 (NUMA) 架构......如果是这种情况,您可能有足够的可用内存,但与直觉相反,仍然没有足够的可用内存。

如果我到目前为止都没有出错的话,那么当 MySQL 尝试增加分配给表的内存时,您可能会遇到此问题MEMORY,并且会遇到与 Linux 在这种架构上运行时处理内存分配的方式相关的错误 - 只考虑直接连接到一个特定 CPU 的内存条上的可用内存,而这个 CPU 被任意选择为可从中处理内存请求的“那个”CPU - 尽管主板上其他地方还有其他物理内存是空闲的。

NUMA 在理论上是好的,但可能并不适合需要大量内存的单个进程,就像 MySQL 的情况一样......但有一个解决方法。

修复方法是修改mysqld_safe脚本,添加以下行:

cmd="/usr/bin/numactl --interleave all $cmd"

...立即地这条线……

cmd="$NOHUP_NICENESS"

这篇优秀的文章解释了其中的原因,它最初是为了解决为什么这种架构的 MySQL 服务器尽管有可用内存,却仍大量进行交换而写的;然而,这是一个更大问题的征兆,作者随后指出“这不完全是交换问题”,即使禁用交换,也可能包括“内存分配失败”。

http://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/

当然,我只是在猜测这是否适用于你的系统,但这似乎是一种值得尝试的可能性。当我在一台新的 128GB 机器上遇到问题时,我使用了这个修复方法,当时我试图配置一个 64GB 的 InnoDB 缓冲池,而 MySQL 无法在一台有没有什么否则正在运行。当我意识到我能成功使用的最高值小于 16 核机器总内存的 1/4 时,其中有 4身体的处理器......有点像你遇到的情况......当我把各个部分放在一起时,就会发现问题的本质。

答案2

文档临时表大小表示此设置是临时表的最大大小在记忆中。超过该大小不会触发任何表已满错误;它会触发从使用内存中的表到使用磁盘上的 MyISAM 表的更改。

系统崩溃是因为你允许临时表占用比应有的更多的内存。内存表也是一样。

你应该删除 tmp_table_size方式减少。请记住,此设置不是总体最大值。它是每个临时表的最大值。如果您有 5 个查询生成一个非常大的临时表(例如每个查询不到 20GB),则现在临时表占用了 100GB 的 RAM。加上第 6 个,您使用的 RAM 已经超过了服务器的总 RAM。

如果您的脚本实际上使用的是 MEMORY 存储引擎,那么在将数据写入 MyISAM 文件之后,您应该考虑进行更改。如果真的需要在如此大的临时表上实现如此快的性能,您应该考虑获取更快的存储(例如。Fusion-io维里登特等)。如果这些太过分或者价格太贵,我至少会考虑消费级 SSD。

当 MyISAM 的数据缓存到系统内存(未使用的 RAM)中时,其性能最佳。如果您的脚本每次执行大型查询(使用 MEMORY 引擎)时都会耗尽缓存,则 MyISAM 性能将受到影响。

我怀疑该脚本正在使用 MEMORY 存储引擎来“提高”性能,但实际上它正在终止它。如果它是一个临时表,它应该使用临时表,并且您的 tmp_table_size 应该小得多,在它破坏 tmp_table_size 后强制将其写入磁盘。

max_heap_table_size 和 tmp_table_size 的默认值均为 16MB。如果可能,我建议将设置改回默认值。在监控资源使用情况(磁盘 i/o、总内存使用情况、CPU 使用情况等)的同时,以小幅度向上调整,直到找到适合您的数据集的设置。

相关内容