GA

2020/09/30

MySQL 8.0.21のDockerイメージがRESTARTステートメントに対応したって話と、そもそもRESTARTステートメントがどうやってmysqldを再起動するのかとって話と

TL;DR

  • RESTART ステートメントの本質は「終了コード16で mysqld を停止」するだけ
    • 親プロセス( mysqld_safe, systemd, dockerd とかとか) が「終了コード16の時はもう一度 mysqld を起動する」という実装をしなければならない
  • RESTART ステートメントの処理の中で、「 SHUTDOWN 権限があるか」「 MYSQLD_PARENT_PID 環境変数がセットされているか」を判定してから、 SIGUSR2 シグナルを使って終了コード16での終了に持っていく
    • 8.0.20までのDockerイメージの entrypoint.shMYSQLD_PARENT_PID を渡していなかったので、その評価のところでfalseになって RESTART はエラーを返していた
    • 8.0.21からの entrypoint.sh はこれを設定するようになったので RESTART ステートメントから「終了コード16で停止」まではわたる。それを起動するには docker run --restart=on-failure にすること(でないと、 RESTART ステートメントが mysqld を停止したところでコンテナが止まって再起動にはならない)
    • 「上位プロセスが mysqld を起動しなおす」ということを押さえておけば、 MYSQLD_PARENT_PID を渡すだけなので汎用性は高そう

RESTART ステートメントを叩き込むと、 mysql_execute_command, Sql_cmd_restart_server::execute, signal_restart_server を通って __pthread_kill でsignel 12(= SIGUSR2 )が呼ばれる。

(gdb) b pthread_kill
+b pthread_kill
Breakpoint 1 at 0x7fcb07702a70: file ../nptl/sysdeps/unix/sysv/linux/pthread_kill.c, line 40.
(gdb) c
+c
(gdb) bt
+bt
#0  __pthread_kill (threadid=140509764310784, signo=signo@entry=12) at ../nptl/sysdeps/unix/sysv/linux/pthread_kill.c:40
#1  0x0000000000dadf0a in signal_restart_server () at /home/yoku0825/mysql-8.0.21/sql/mysqld.cc:2330
#2  0x0000000000efa1bd in Sql_cmd_restart_server::execute(THD*) () at /home/yoku0825/mysql-8.0.21/sql/sql_restart_server.cc:78
#3  0x0000000000ead21f in mysql_execute_command(THD*, bool) () at /home/yoku0825/mysql-8.0.21/sql/sql_parse.cc:4573
#4  0x0000000000eb217f in mysql_parse (thd=thd@entry=0x7fcaac0d0390, parser_state=parser_state@entry=0x7fcafa924510)
    at /home/yoku0825/mysql-8.0.21/sql/sql_parse.cc:5393
#5  0x0000000000eb42c0 in dispatch_command(THD*, COM_DATA const*, enum_server_command) ()
    at /home/yoku0825/mysql-8.0.21/sql/sql_parse.cc:1810
#6  0x0000000000eb5034 in do_command (thd=thd@entry=0x7fcaac0d0390) at /home/yoku0825/mysql-8.0.21/sql/sql_parse.cc:1294
#7  0x0000000000fcd330 in handle_connection (arg=arg@entry=0x62ab490)
    at /home/yoku0825/mysql-8.0.21/sql/conn_handler/connection_handler_per_thread.cc:302
#8  0x000000000260c2be in pfs_spawn_thread (arg=0x62e7040) at /home/yoku0825/mysql-8.0.21/storage/perfschema/pfs.cc:2880
#9  0x00007fcb076fdea5 in start_thread (arg=0x7fcafa925700) at pthread_create.c:307
#10 0x00007fcb05ae18dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

mysqldSIGUSR2 を受け取ると signal_hand_thr_exit_code = MYSQLD_RESTART_EXIT をセットして ( MYSQLD_RESTART_EXITは16 ) 終了する ( case の中で break しないのでそのまま SIGTERM, SIGQUIT と同じ処理に流れる)

たとえば mysqld_safe はこんな風に終了コードを見て、再起動するかそのまま正常終了するかを決めていたりする。

このへんの仕組みを知っていれば、標準以外の環境でも RESTART ステートメントを使えるようにするにできる気がする。

0 件のコメント :

コメントを投稿