max_heap_table_size の値を増やすと MySQL がクラッシュする

max_heap_table_size の値を増やすと MySQL がクラッシュする

120 GB の RAM を搭載した Ubuntu 12.04 サーバーで MySQL インスタンスを実行しています。このサーバーではいくつかの PHP スクリプトが実行されており、新しい mysql パラメータを設定することがあります。これらのスクリプトの 1 つは、MySISAM テーブルに挿入する前に、大きな MEMORY テーブルを使用してデータを統合します。

最近、「テーブルがいっぱいです」というエラーを回避するために、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.

クラッシュ/再起動は 1 時間後に発生しました。

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 または slow-query ログ出力はありませんが、スタック トレースが生成された後に PHP スクリプトが引き続き実行されたことは言えます。mysql の再起動中に停止しました。

このエラーはすでに 2 つの異なるサーバーで発生しているため、ハードウェア障害は考慮されません。

クラッシュの原因は何でしょうか? MySQL をクラッシュさせずに使用できる最大の max_heap_table_size と tmp_table_size を調べるにはどうすればよいですか?

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

120 GB のメモリがある場合、マシンに複数の物理 CPU と Non-Uniform Memory Access (NUMA) アーキテクチャが搭載されている可能性もあります...その場合、使用可能なメモリは十分にある可能性がありますが、直感に反して、使用可能なメモリがまだ十分ではない可能性があります。

これまでのところ私の推測が正しいとすれば、この問題は、MySQL がテーブルに割り当てられたメモリを増やそうとしたときに発生する可能性があります。このとき、MEMORYLinux がこのアーキテクチャで実行しているときにメモリ割り当てを処理する方法に関連するエラーが発生します。つまり、マザーボード上の他の物理メモリが空いているにもかかわらず、メモリ要求が処理される「1 つ」としてある程度恣意的に選択された特定の 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が64GBの空き容量を見つけられなかったという問題に遭遇したときに、まさにこの修正を使用しました。何もない他に実行中のものはありません。私がうまく使用できる最高の値は、4つのコアを持つ16コアマシンの合計メモリの1/4未満であることに気づきました。物理的なプロセッサ... あなたが遭遇しているようなもの... 問題の本質について私が情報をまとめたとき、それが分かりました。

答え2

ドキュメントtmp_テーブルサイズこの設定は一時テーブルの最大サイズですメモリ内このサイズを超えても、テーブルがいっぱいであるというエラーは発生しません。メモリ内のテーブルの使用からディスク上の MyISAM テーブルの使用への変更がトリガーされます。

システムがクラッシュするのは、一時テーブルが本来よりも多くのメモリを使用することを許可しているためです。メモリ テーブルについても同様です。

tmp_table_sizeを削除する必要があります方法ダウンします。この設定は全体の最大値ではなく、一時テーブルごとの最大値であることに注意してください。非常に大きな一時テーブルを作成するクエリが 5 つある場合 (それぞれ 20 GB 未満など)、一時テーブルが RAM の 100 GB を使用することになります。6 つ目を追加すると、サーバーの合計よりも多くの RAM が使用されることになります。

スクリプトが実際に MEMORY ストレージ エンジンを使用している場合は、MyISAM ファイルにデータを書き込む前に、その変更を検討する必要があります。その大きさの一時テーブルでその高速パフォーマンスが本当に必要な場合は、より高速なストレージ (例:フュージョン-ioヴィリデントなど)。それらが過剰であったり高価すぎる場合は、少なくとも消費者向けグレードの SSD を検討します。

MyISAM は、データがシステム メモリ (未使用の RAM) にキャッシュされているときに最高のパフォーマンスを発揮します。スクリプトが巨大なクエリ (MEMORY エンジンを使用) を実行するたびにキャッシュを使い果たしてしまうと、MyISAM のパフォーマンスが低下します。

スクリプトは MEMORY ストレージ エンジンを使用してパフォーマンスを「向上」させているように見えますが、実際にはパフォーマンスを低下させています。一時テーブルの場合は、一時テーブルを使用する必要があり、tmp_table_size はもっと小さい値に設定して、tmp_table_size を超えたらディスクに強制的に書き込む必要があります。

max_heap_table_size と tmp_table_size のデフォルトはどちらも 16 MB です。可能であれば、設定をデフォルトに戻すことをお勧めします。リソース使用量 (ディスク I/O、合計メモリ使用量、CPU 使用量など) を監視しながら、データ セットに適した設定が見つかるまで少しずつ上方に調整します。

関連情報