Edited at

MySQLが統計情報を計算するタイミングで再起動してしまう

More than 1 year has passed since last update.


対象バージョン

MySQL 5.6.35, 5.7.17


現象

AWS より RDS 上の MySQL のうち 5.6.19a, 5.6.19b, 5.6.21, 5.6.21b, 5.6.22, and 5.6.23 の各バージョンが廃止となるという連絡があり、その時点での最新バージョンである 5.6.35 にアップデートを実施した。

するとバージョンアップ後しばらくして以下のエラーが発生し、断続的に再起動を繰り返すようになってしまった。

(ログは一部改変しています)

terminate called after throwing an instance of 'std::out_of_range'

what(): vector::_M_range_check
06:01:31 UTC - mysqld got signal 6 ;
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=xxxxxxxx
read_buffer_size=xxxxxxxx
max_used_connections=xxxx
max_threads=xxxx
thread_count=xxxx
connection_count=xxxx
It is possible that mysqld could use up to
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = xxxxxx K bytes of memory
Hope that's ok; if not, decrease some variables in the equation.
Thread pointer: 0x0
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 = 0 thread_stack 0x40000
/rdsdbbin/mysql/bin/mysqld(my_print_stacktrace+0x33)[0x876d73]
/rdsdbbin/mysql/bin/mysqld(handle_fatal_signal+0x35c)[0x64089c]
/lib64/libpthread.so.0(+0x10f90)[0x7fecc63d2f90]
/lib64/libc.so.6(gsignal+0x37)[0x7fecc57e8167]
/lib64/libc.so.6(abort+0x16a)[0x7fecc57e95ea]
/usr/lib64/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x16d)[0x7fecc60e017d]
/usr/lib64/libstdc++.so.6(+0x73fc6)[0x7fecc60ddfc6]
/usr/lib64/libstdc++.so.6(+0x74011)[0x7fecc60de011]
/usr/lib64/libstdc++.so.6(+0x74228)[0x7fecc60de228]
/usr/lib64/libstdc++.so.6(_ZSt20__throw_out_of_rangePKc+0x139)[0x7fecc613e869]
/rdsdbbin/mysql/bin/mysqld[0xa8e394]
/rdsdbbin/mysql/bin/mysqld[0xa8fb59]
/rdsdbbin/mysql/bin/mysqld[0xa90ec0]
/lib64/libpthread.so.0(+0x7f18)[0x2ada4e15bf18]
/lib64/libc.so.6(clone+0x6d)[0x2ada4f2a5b2d]
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.


原因

以下 URL にある通り、MySQL の 5.6.35, 5.7.17 でのみ発生するバグとのこと。

https://bugs.mysql.com/bug.php?id=84940


対応

以下2つの対応方法がある。


1. 問題のあるバージョンを回避する

次のバージョンで FIX されているため、5.6.36, 5.7.18 以降のバージョンにアップデートすればよい。

ただ、RDS の場合はちょっと厄介で、2017/8/14 の時点では 5.7.18 以降を選択できないため、5.7.17 になっている場合はダウングレードが必要となってしまう。

(問題の発生した環境は運良く 5.6.35 だったので、5.7.16 にバージョンアップをすることで回避できた)

RDS は現在より前のバージョンを選択できず、スナップショットからの復元でもバージョンは選択できないので、新たにインスタンスを立ち上げて、そこにデータを流し込む方法になると思われる。


2. インデックス統計を永続化しない

前述の URL によると、削除行のインデックス統計判定の不具合(※MariaDBでの修正箇所です)が原因とのこと。

なので、クエリパラメータより以下の設定をすればよいらしい。

[mysqld]

innodb-stats-persistent = 0
innodb-stats-transient-sample-pages = 20
innodb-stats-auto-recalc = 0

ただし、この変更によりインデックス統計が非永続的になり、性能劣化が予測されるため、今回は選択しなかった。


備考

MySQL 5.6 と 5.7 の互換性に注意が必要である。

ハマったところで言うと、以下の2つ。


  • sql_mode の ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE がデフォルトで ON

  • ROW_FORMAT=FIXED が廃止

RDS の場合は新しいパラメータグループを作成するが、複数のパラメータグループを比較できるので、それを利用すれば分かりやすいかもしれない。

スクリーンショット 2017-08-15 11.40.15.png

character_set_server を latin1 から utf8mb4 にしなければいけないのもここで気づくことができた。