MySQL 起動時に「サーバーは PID ファイルを更新せずに終了しました」というエラーが報告される理由の詳細な分析

MySQL 起動時に「サーバーは PID ファイルを更新せずに終了しました」というエラーが報告される理由の詳細な分析

多くの人が MySQL の起動時にこのエラーに遭遇しています。

まず、このエラーの前提は、サービス スクリプトを通じて mysql を起動することであることを明確にしておきます。 mysqld_safe または mysqld を介して MySQL インスタンスを起動すると、このエラーは報告されません。

それで、このエラーの具体的な理由は何でしょうか?

ハハハ、分析の過程を気にしないなら、記事の最後にある要約に直接飛んでもいいですよ〜

要約する

次に、mysqlサービスの起動スクリプトを分析してみましょう。

完全なスクリプトは次のとおりです。

#!/bin/sh
# 著作権放棄 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
# このファイルはパブリックドメインであり、いかなる種類の保証もありません
# MySQL デーモンの起動/停止スクリプト。
# 通常、これは/etc/init.d(少なくともSYSV R4ベースのマシンでは)に配置されます
# システム) にインストールされ、/etc/rc3.d/S99mysql および /etc/rc0.d/K01mysql にリンクされています。
# これが完了すると、マシンの電源が入ったときにmysqlサーバーが起動します。
# システムがダウンすると起動およびシャットダウンします。
# RedHat Linux で chkconfig をサポートするためのコメント
# chkconfig: 2345 64 36
# 説明: 非常に高速で信頼性の高い SQL データベース エンジン。
# LSB 初期化スクリプトの規則をサポートするためのコメント
### 初期化情報の開始
# 提供: mysql
# 必須開始: $local_fs $network $remote_fs
# 開始すべきもの: ypbind nscd ldap ntpd xntpd
# 必須停止: $local_fs $network $remote_fs
# デフォルト開始: 2 3 4 5
# デフォルト停止: 0 1 6
# 簡単な説明: MySQL の起動と停止
# 説明: MySQL は非常に高速で信頼性の高い SQL データベース エンジンです。
### 初期化情報の終了
# MySQLを/usr/local/mysql以外の場所にインストールする場合は、
# このスクリプトが動作するには、次のいずれかを実行する必要があります。
#
# - MySQLインストールディレクトリ内からこのスクリプトを実行します
# - 次の情報を含む /etc/my.cnf ファイルを作成します。
# [mysqld]
# basedir=<mysql インストールディレクトリへのパス>
# - 上記を他の設定ファイル(例: ~/.my.ini)に追加します。
# そしてmy_print_defaultsを/usr/binにコピーします
# - mysqlインストールディレクトリへのパスをbasedir変数に追加します
# 下に。
#
# 他のMySQL変数に影響を与えたい場合は、変更を加える必要があります
# /etc/my.cnf、~/.my.cnf またはその他の MySQL 構成ファイル内。
# ベースディレクトリを変更する場合は、データディレクトリも変更する必要があります。
# MySQL 構成ファイルの設定によって上書きされます。
ベースディレクトリ=
データディレクトリ=
# スクリプトがタイムアウトするまでのデフォルト値(秒数)。
# サーバーの起動用。 
# ここでの値は my.cnf の値によって上書きされます。 
# 0 は全く待たないことを意味する
# 負の数は無期限に待機することを意味します
サービス起動タイムアウト=900
# RedHat / SuSE のディレクトリをロックします。
ロックディレクトリ='/var/lock/subsys'
lock_file_path="$lockdir/mysql"
# 以下の変数は、mysql.server が検索できるようにするためにのみ設定されます。
# デフォルトを設定する
mysqld_pid_file_path=
if test -z "$basedir"
それから
 ベースディレクトリ=/usr/local/mysql
 バインドディレクトリ=/usr/local/mysql/bin
 テスト -z "$datadir"
 それから
 データディレクトリ=/usr/local/mysql/data
 フィ
 sbindir=/usr/local/mysql/bin
 libexecdir=/usr/local/mysql/bin
それ以外
 bindir="$basedir/bin"
 テスト -z "$datadir"
 それから
 datadir="$basedir/data"
 フィ
 sbindir="$basedir/sbin"
 libexecdir="$basedir/libexec"
フィ
# datadir_setは、datadirが設定されているかどうかを判断するために使用されます(したがって、
# --basedir= ハンドラ内では設定されません。
データディレクトリ設定=
#
# 可能であれば、メッセージを印刷するために LSB 初期化スクリプト関数を使用する
#
lsb_functions="/lib/lsb/init-functions"
テスト -f $lsb_functions の場合;
 . $lsb_functions
それ以外
 ログ成功メッセージ()
 {
 echo " 成功しました! $@"
 }
 ログ失敗メッセージ()
 {
 echo " エラー! $@"
 }
フィ
PATH="/sbin:/usr/sbin:/bin:/usr/bin:$basedir/bin"
エクスポートPATH
mode=$1 # 開始または停止
[ $# -ge 1 ] && シフト
other_args="$*" # 一般的ではありませんが、RPM アップグレード アクションから呼び出される場合は必要です
   # 期待値: "--skip-networking --skip-grant-tables"
   # 責任は負わないので、ここでは意図的にチェックしません
   # 「spec」ファイルの作成者は正しい引数のみを与える必要があります。
case `echo "testing\c"`,`echo -n testing` の場合
 *c*,-n*) echo_n= echo_c= ;;
 *c*,*) echo_n=-n echo_c= ;;
 *) echo_n= echo_c='\c' ;;
エサック
parse_server_arguments() {
 引数に対して
 ケース「$arg」
  --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'`
     bindir="$basedir/bin"
   テスト -z "$datadir_set" の場合、
    datadir="$basedir/data"
   フィ
   sbindir="$basedir/sbin"
   libexecdir="$basedir/libexec"
  ;;
  --datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'`
   データディレクトリセット=1
 ;;
  --pid-file=*) mysqld_pid_file_path=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
  --service-startup-timeout=*) service_startup_timeout=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
 エサック
 終わり
}
wait_for_pid() {
 verb="$1" # 作成 | 削除
 pid="$2" # pidファイルで動作するプログラムのプロセスID
 pid_file_path="$3" # PID ファイルへのパス。
 私=0
 競合状態を回避するには、「再度確認する」
 $i -ne $service_startup_timeout をテストしながら実行します。
 case "$verb" の場合
  '作成された')
  # PID ファイルが存在するようになるまで待機します。
  テスト -s "$pid_file_path" && i='' && break
  ;;
  '削除')
  # このPIDファイルが消えるまで待つ
  テスト! -s "$pid_file_path" && i='' && break
  ;;
  *)
  echo "wait_for_pid () の使用法: wait_for_pid が作成されました| pid pid_file_path が削除されました"
  出口1
  ;;
 エサック
 # サーバーが稼働していない場合、pid ファイルは更新されません
 テスト -n "$pid"; の場合
  kill -0 "$pid" 2>/dev/null;の場合
  : # サーバーはまだ稼働しています
  それ以外
  # 最後の pid ファイル チェックと現在の間にサーバーが終了した可能性があります。 
  テスト -n "$avoid_race_condition"; の場合
   競合状態を回避する=""
   続行 # もう一度確認してください。
  フィ
  # ファイルに影響を与えるものは何もありません。
  log_failure_msg "サーバーは PID ファイル ($pid_file_path) を更新せずに終了しました。"
  return 1 # これ以上待機しません。
  フィ
 フィ
 エコー $echo_n ".$echo_c"
 i=`式 $i + 1`
 睡眠1
 終わり
 テスト -z "$i" の場合;
 ログ成功メッセージ
 0を返す
 それ以外
 ログ失敗メッセージ
 戻り値 1
 フィ
}
# my.cnfファイルから引数を取得し、
# これから読み込まれる唯一のグループは [mysqld] です
テストの場合 -x ./bin/my_print_defaults
それから
 print_defaults="./bin/my_print_defaults"
elif テスト -x $bindir/my_print_defaults
それから
 print_defaults="$bindir/my_print_defaults"
elif テスト -x $bindir/mysql_print_defaults
それから
 print_defaults="$bindir/mysql_print_defaults"
それ以外
 # /etc/my.cnf で basedir を探します
 conf=/etc/my.cnf
 印刷デフォルト=
 テスト -r $conf
 それから
 サブパット='^[^=]*basedir[^=]*=\(.*\)$'
 dirs=`sed -e "/$subpat/!d" -e 's//\1/' $conf`
 $dirs 内の d の場合
 する
  d=`echo $d | sed -e 's/[ ]//g'`
  テスト -x "$d/bin/my_print_defaults"
  それから
  print_defaults="$d/bin/my_print_defaults"
  壊す
  フィ
  テストの場合 -x "$d/bin/mysql_print_defaults"
  それから
  print_defaults="$d/bin/mysql_print_defaults"
  壊す
  フィ
 終わり
 フィ
 # PATH にあるといいのですが...疑わしいです
 テスト -z "$print_defaults" && print_defaults="my_print_defaults"
フィ
#
# 'basedir'からデフォルトファイルを読み込みます。そこにデフォルトファイルがない場合
# 古い(非推奨の)場所(datadir)にあるかどうかを確認し、そこから読み取ります
#
追加引数=""
テスト -r "$basedir/my.cnf"
それから
 extra_args="-e $basedir/my.cnf"
それ以外
 テスト -r "$datadir/my.cnf"
 それから
 extra_args="-e $datadir/my.cnf"
 フィ
フィ
parse_server_arguments `$print_defaults $extra_args mysqld サーバー mysql_server mysql.server`
#
# 指定されていない場合はPIDファイルを設定する
#
テスト -z "$mysqld_pid_file_path" の場合
それから
 mysqld_pid_file_path=$datadir/`ホスト名`.pid
それ以外
 ケース「$mysqld_pid_file_path」
 /* ) ;;
 * )mysqld_pid_file_path="$datadir/$mysqld_pid_file_path" ;;
 エサック
フィ
ケース「$mode」
 '始める')
 # デーモンを起動
 # セーフガード (相対パス、コアダンプなど)
 cd $ベースディレクトリ
 echo $echo_n "MySQL を起動しています"
 テストの場合 -x $bindir/mysqld_safe
 それから
  # my.cnfファイルでmysqldに追加の引数を与えます。このスクリプト
  # 次回のアップグレード時に上書きされる可能性があります。
  $bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &
  wait_for_pid が "$!" "$mysqld_pid_file_path" を作成しました。 return_value=$?
  # RedHat / SuSE 用のロックを作成する
  テスト -w "$lockdir"
  それから
  「$lock_file_path」をタッチします
  フィ
  終了 $return_value
 それ以外
  log_failure_msg "MySQL サーバーが見つかりませんでした ($bindir/mysqld_safe)"
 フィ
 ;;
 '停止')
 # デーモンを停止します。ここでは、
 # ルートパスワード。
 テスト -s "$mysqld_pid_file_path" の場合
 それから
  mysqld_pid=`cat "$mysqld_pid_file_path"`
  (kill -0 $mysqld_pid 2>/dev/null)の場合
  それから
  echo $echo_n "MySQL をシャットダウンしています"
  $mysqld_pid を強制終了する
  # mysqld は終了時に pid ファイルを削除するはずなので、それを待ちます。
  wait_for_pid が "$mysqld_pid" "$mysqld_pid_file_path" を削除しました。 return_value=$?
  それ以外
  log_failure_msg "MySQL サーバー プロセス #$mysqld_pid が実行されていません!"
  rm "$mysqld_pid_file_path"
  フィ
  # RedHat / SuSE のロックを削除
  テスト -f "$lock_file_path"
  それから
  rm -f "$lock_file_path"
  フィ
  終了 $return_value
 それ以外
  log_failure_msg "MySQL サーバーの PID ファイルが見つかりませんでした!"
 フィ
 ;;
 '再起動')
 # サービスを停止し、
 # 実行中かどうかにかかわらず、もう一度起動してください。
 $0の場合は$other_argsを停止します。
  $0 開始 $other_args
 それ以外
  log_failure_msg 「実行中のサーバーを停止できなかったため、起動を試行しません。」
  出口1
 フィ
 ;;
 'リロード'|'強制リロード')
 テスト -s "$mysqld_pid_file_path" の場合、
  mysqld_pid を読み取り < "$mysqld_pid_file_path"
  kill -HUP $mysqld_pid && log_success_msg "MySQL サービスを再ロードしています"
  "$mysqld_pid_file_path" をタッチします
 それ以外
  log_failure_msg "MySQL PID ファイルが見つかりませんでした!"
  出口1
 フィ
 ;;
 '状態')
 # まず、pidファイルが存在するかどうかを確認します
 テスト -s "$mysqld_pid_file_path" の場合、 
  mysqld_pid を読み取り < "$mysqld_pid_file_path"
  kill -0 $mysqld_pid 2>/dev/nullの場合; 
  log_success_msg "MySQL が実行中です ($mysqld_pid)"
  終了 0
  それ以外
  log_failure_msg 「MySQL は実行されていませんが、PID ファイルは存在します」
  出口1
  フィ
 それ以外
  # 適切なmysqldプロセスを探します
  mysqld_pid=`pidof $libexecdir/mysqld`
  # 複数のPIDが存在するかどうかをテストする
  pid_count=`echo $mysqld_pid | wc -w`
  $pid_count -gt 1 をテストする場合、
  log_failure_msg "複数の MySQL が実行中ですが、PID ファイルが見つかりません ($mysqld_pid)"
  出口5
  elif test -z $mysqld_pid; その後 
  テスト -f "$lock_file_path" の場合; 
   log_failure_msg "MySQL は実行されていませんが、ロック ファイル ($lock_file_path) が存在します"
   出口2
  フィ 
  log_failure_msg 「MySQL が実行されていません」
  出口3
  それ以外
  log_failure_msg 「MySQL は実行されていますが、PID ファイルが見つかりませんでした」
  出口4
  フィ
 フィ
 ;;
 *)
  # 使用法
  ベース名=`ベース名 "$0"`
  echo "使用方法: $basename {start|stop|restart|reload|force-reload|status} [ MySQL サーバー オプション ]"
  出口1
 ;;
エサック
終了 0

まず、関連するパラメータを定義します

ベースディレクトリ=
データディレクトリ=
# スクリプトがタイムアウトするまでのデフォルト値(秒数)。
# サーバーの起動用。 
# ここでの値は my.cnf の値によって上書きされます。 
# 0 は全く待たないことを意味する
# 負の数は無期限に待機することを意味します
サービス起動タイムアウト=900
# RedHat / SuSE のディレクトリをロックします。
ロックディレクトリ='/var/lock/subsys'
lock_file_path="$lockdir/mysql"

で、

basedir は、バイナリ圧縮パッケージが解凍されるディレクトリ (例: /usr/local/mysql) を指します。

datadirはデータディレクトリを指します

service_startup_timeout=900 は、MySQL サービスを開始するための時間制限を定義します。900 秒以内にサービスが開始しない場合、スクリプトは終了します。

ロックディレクトリ='/var/lock/subsys'

/var/lock/subsys に関しては、インターネット上の説明が以下の通りで、後ほど参考にさせていただきます。

一般的に、システム シャットダウン プロセス (シャットダウン信号を発行し、サービスの独自のプロセスを呼び出す) は、/var/lock/subsys の下のファイルをチェックし、各サービスを 1 つずつシャットダウンします。実行中のサービスに /var/lock/subsys の下に対応するオプションがない場合。システムがシャットダウンされると、このサービスは通常のプロセスと同様に終了されます。

/etc/rc.d/init.d の下のスクリプトを見ると、各サービスが動作する際に、/var/lock/subsys の下の対応するサービスをチェックしていることがわかります。

多くのプログラムでは、すでにインスタンスが実行中であるかどうかを判断する必要があります。このディレクトリは、プログラムがインスタンスが実行中であるかどうかを判断するためのサインです。たとえば、このファイルが存在する場合、xinetd がすでに実行中であることを意味します。そうでない場合は実行されていません。もちろん、インスタンスが実行中であるかどうかを実際に判断するには、プログラム内に対応する判断基準が必要です。通常、このディレクトリには /var/run ディレクトリが付随しており、対応するインスタンスの PID を保存するために使用されます。スクリプトを作成すると、これら 2 つのディレクトリを組み合わせることで、多くのサービスが実行中かどうか、実行中の関連情報などを簡単に判断できることがわかります。

ベースディレクトリとデータディレクトリを決定する

# デフォルトを設定する
mysqld_pid_file_path=
if test -z "$basedir"
それから
 ベースディレクトリ=/usr/local/mysql
 バインドディレクトリ=/usr/local/mysql/bin
 テスト -z "$datadir"
 それから
 データディレクトリ=/usr/local/mysql/data
 フィ
 sbindir=/usr/local/mysql/bin
 libexecdir=/usr/local/mysql/bin
それ以外
 bindir="$basedir/bin"
 テスト -z "$datadir"
 それから
 datadir="$basedir/data"
 フィ
 sbindir="$basedir/sbin"
 libexecdir="$basedir/libexec"
フィ

で、

mysqld_pid_file_pathはpidファイルへのパスを指定します

-z 文字列は文字列が空かどうかを決定します

basedir が明示的に設定されていない場合、デフォルトは /usr/local/mysql です。このため、多くの MySQL インストール チュートリアルでは、MySQL 関連のファイルを /usr/local/mysql に配置することを推奨しています。

datadir が明示的に設定されていない場合は、デフォルトで $basedir/data になります。

log_success_msg() および log_failure_msg() 関数を定義する

まず、/lib/lsb/init-functions ファイルが存在するかどうかを確認します。存在する場合は、init-functions ファイルで定義されているすべてのシェル関数を現在のスクリプトで有効にします。

そうでない場合は、成功ログを印刷するための関数とエラー ログを印刷するための関数の 2 つを定義します。

RHCS 6.7 では、このファイルは存在せず、/etc/init.d/functions に置き換えられました。

#
# 可能であれば、メッセージを印刷するために LSB 初期化スクリプト関数を使用する
#
lsb_functions="/lib/lsb/init-functions"
テスト -f $lsb_functions の場合;
 . $lsb_functions
それ以外
 ログ成功メッセージ()
 {
 echo " 成功しました! $@"
 }
 ログ失敗メッセージ()
 {
 echo " エラー! $@"
 }
フィ

パラメータの受け渡し

最初の引数をmodeに渡し、残りの引数をother_argsに渡します。

PATH="/sbin:/usr/sbin:/bin:/usr/bin:$basedir/bin"
エクスポートPATH
mode=$1 # 開始または停止
[ $# -ge 1 ] && シフト
other_args="$*" # 一般的ではありませんが、RPM アップグレード アクションから呼び出される場合は必要です
   # 期待値: "--skip-networking --skip-grant-tables"
   # 責任は負わないので、ここでは意図的にチェックしません
   # 「spec」ファイルの作成者は正しい引数のみを与える必要があります。
case `echo "testing\c"`,`echo -n testing` の場合
 *c*,-n*) echo_n= echo_c= ;;
 *c*,*) echo_n=-n echo_c= ;;
 *) echo_n= echo_c='\c' ;;
エサック

設定ファイル内のパラメータの解析

この関数はスクリプトの後半で参照されます。

関係する主なパラメータは、--basedir、--datadir、--pid-file、--service-startup-timeout です。

parse_server_arguments() {
 引数に対して
 ケース「$arg」
  --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'`
     bindir="$basedir/bin"
   テスト -z "$datadir_set" の場合、
    datadir="$basedir/data"
   フィ
   sbindir="$basedir/sbin"
   libexecdir="$basedir/libexec"
  ;;
  --datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'`
   データディレクトリセット=1
 ;;
  --pid-file=*) mysqld_pid_file_path=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
  --service-startup-timeout=*) service_startup_timeout=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
 エサック
 終わり
}

my_print_defaultsの場所を特定する

まず、現在のパスの下の bin ディレクトリに実行可能ファイルが存在するかどうかを確認します。存在しない場合は、$bindir (通常は $basedir/bin) ディレクトリに存在するかどうかを確認します。

それでも存在しない場合は、/etc/my.cnf が存在し、読み取り可能であるかどうかを判断します。存在する場合は、設定ファイルで basedir パラメータが指定されているかどうかを判断します。

指定されている場合、パラメータの値を取得し、その値に対応するディレクトリに bin/my_print_defaults 実行可能ファイルがあるかどうかを判断します。

最後のステップとして、上記のディレクトリにmy_print_defaultsファイルが見つからない場合は、

単に print_defaults を "my_print_defaults" に設定し、コマンドが現在の PATH 環境にあることを期待します。

# my.cnfファイルから引数を取得し、
# これから読み込まれる唯一のグループは [mysqld] です
テストの場合 -x ./bin/my_print_defaults
それから
 print_defaults="./bin/my_print_defaults"
elif テスト -x $bindir/my_print_defaults
それから
 print_defaults="$bindir/my_print_defaults"
elif テスト -x $bindir/mysql_print_defaults
それから
 print_defaults="$bindir/mysql_print_defaults"
それ以外
 # /etc/my.cnf で basedir を探します
 conf=/etc/my.cnf
 印刷デフォルト=
 テスト -r $conf
 それから
 サブパット='^[^=]*basedir[^=]*=\(.*\)$'
 dirs=`sed -e "/$subpat/!d" -e 's//\1/' $conf`
 $dirs 内の d の場合
 する
  d=`echo $d | sed -e 's/[ ]//g'`
  テスト -x "$d/bin/my_print_defaults"
  それから
  print_defaults="$d/bin/my_print_defaults"
  壊す
  フィ
  テストの場合 -x "$d/bin/mysql_print_defaults"
  それから
  print_defaults="$d/bin/mysql_print_defaults"
  壊す
  フィ
 終わり
 フィ
 # PATH にあるといいのですが...疑わしいです
 テスト -z "$print_defaults" && print_defaults="my_print_defaults"
フィ

デフォルトの設定ファイルを見つける

-r ファイル ファイルが読み取り可能な場合は真

#
# 'basedir'からデフォルトファイルを読み込みます。そこにデフォルトファイルがない場合
# 古い(非推奨の)場所(datadir)にあるかどうかを確認し、そこから読み取ります
#
追加引数=""
テスト -r "$basedir/my.cnf"
それから
 extra_args="-e $basedir/my.cnf"
それ以外
 テスト -r "$datadir/my.cnf"
 それから
 extra_args="-e $datadir/my.cnf"
 フィ
フィ

設定ファイル内のパラメータの解析

my_print_defaults の使用方法は次のとおりです。

my_print_defaults --defaults-file=example.cnf クライアント mysql

つまり、設定ファイル内のクライアントと mysql 部分のパラメータ設定を読み取ります。

具体的には、このスクリプトでは、mysqld、server、mysql_server、および mysql.server の構成パラメータが読み取られます。

parse_server_arguments `$print_defaults $extra_args mysqld サーバー mysql_server mysql.server`

pidファイルへのパスを設定する

-z 文字列は文字列が空かどうかを決定します

--pid-fileが読み込まれた設定ファイルに設定されていない場合、またはスクリプトの先頭でmysqld_pid_file_pathパラメータが設定されていない場合、

pid ファイルはデフォルトで datadir の下に設定され、hostname.pid という名前が付けられます。

このパラメータが設定されている場合は、さらに判断が必要です

このパラメータにスラッシュが含まれている場合、指定された値にパスがあり、直接使用できることを意味します。

このパラメータにパスがない場合、指定された値は datadir で設定できる pid のファイル名のみであることを意味します。

#
# 指定されていない場合はPIDファイルを設定する
#
テスト -z "$mysqld_pid_file_path" の場合
それから
 mysqld_pid_file_path=$datadir/`ホスト名`.pid
それ以外
 ケース「$mysqld_pid_file_path」
 /* ) ;;
 * )mysqld_pid_file_path="$datadir/$mysqld_pid_file_path" ;;
 エサック
フィ

サービススクリプトの起動オプション

まず、$basedirに切り替えます

次に、$basedir/bin 内の mysqld_safe が実行可能ファイルであるかどうかを判断します。実行可能ファイルである場合は、mysqld インスタンスを起動します。実行可能ファイルでない場合は、エラーを報告して終了します。

では、起動プロセスはどのように実装されるのでしょうか?

まず、$bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 & コマンドを実行して、mysqld インスタンスを起動します。

mysqld_safe は、mysql 初期化スクリプト mysql_install_db も含めて、実際には basedir で実行されることにお気づきでしたか。これも basedir で実行することをお勧めします。詳細については、以下を参照してください。

MariaDB 初期化スクリプト mysql_install_db の分析

次に wait_for_pid 関数を使用して判定します。詳細については、以下の wait_for_pid 関数の分析を参照してください。

判決が下されると、

$lockdir ディレクトリが書き込み可能かどうかを確認します。書き込み可能な場合は、ディレクトリ内にファイルを作成します。

ケース「$mode」
 '始める')
 # デーモンを起動
 # セーフガード (相対パス、コアダンプなど)
 cd $ベースディレクトリ
 echo $echo_n "MySQL を起動しています"
 テストの場合 -x $bindir/mysqld_safe
 それから
  # my.cnfファイルでmysqldに追加の引数を与えます。このスクリプト
  # 次回のアップグレード時に上書きされる可能性があります。
  $bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &
  wait_for_pid が "$!" "$mysqld_pid_file_path" を作成しました。 return_value=$?
  # RedHat / SuSE 用のロックを作成する
  テスト -w "$lockdir"
  それから
  「$lock_file_path」をタッチします
  フィ
  終了 $return_value
 それ以外
  log_failure_msg "MySQL サーバーが見つかりませんでした ($bindir/mysqld_safe)"
 フィ
 ;;

wait_for_pid 関数

mysqld_safeを使用してMySQLインスタンスを起動した後、このパラメータが呼び出されます

wait_for_pid が "$!" "$mysqld_pid_file_path" を作成しました。 return_value=$?

$! は、シェルで最後に実行されたバックグラウンド プロセスの PID を取得するために使用されます。この場合、それは mysqld_safe プロセスの PID です。

最初のパラメータが作成されるため、 test -s "$pid_file_path" && i='' && breakコマンドが実行されます。

-s ファイル ファイルの長さがゼロでない場合は真

このコマンドは、pid ファイルが存在する場合、変数 i が空に設定され、while ループが終了することを意味します。

次に、次の判断を実行します。

テスト -z "$i" の場合;
 ログ成功メッセージ
 0を返す
 それ以外
 ログ失敗メッセージ
 戻り値 1
 フィ

$i が空の場合、成功ログが出力され、スクリプトは終了します。当然、pid ファイルが存在する場合、変数 i は空に設定されます。

pidファイルが存在しない状況を見てみましょう

まず、$pidが空でないかどうかを確認します(つまり、test -n "$pid"の場合)。

空でない場合は、mysqld_safe の実行後にプロセスの pid が取得されたことを意味します。

この場合、kill -0 "$pid" を使用してプロセスが存在するかどうかをさらに確認します。

kill -0 はシグナルを送信しませんが、システムはエラーチェックを実行するため、プロセスが存在するかどうかを確認するためによく使用されます。プロセスが存在しない場合は、kill -0 pid はエラーを返します。

プロセスが存在する場合、操作は実行されず、次の操作は直接スキップされます。

エコー $echo_n ".$echo_c"
i=`式 $i + 1`
睡眠1

変数 i を 1 増やし、1 秒間スリープします。

次に、while ループを続行します。これを行う理由は、mysqld_safe は実行されましたが、mysqld インスタンスはまだ起動プロセスにあり、pid ファイルはまだ作成されていないためです。

$1 が $service_startup_timeout で定義された期間に達するまで。

whileループ中にkill -0 "$pid"を使用してプロセスが存在しないと判断した場合、

再度判定します。この判定の結果、pidファイルが存在せず、プロセスも存在しない場合は、

log_failure_msg "サーバーは PID ファイル ($pid_file_path) を更新せずに終了しました。"

これが有名な「サーバーは PID ファイルを更新せずに終了しました」の原因です。

wait_for_pid() {
 verb="$1" # 作成 | 削除
 pid="$2" # pidファイルで動作するプログラムのプロセスID
 pid_file_path="$3" # PID ファイルへのパス。
 私=0
 競合状態を回避するには、「再度確認する」
 $i -ne $service_startup_timeout をテストしながら実行します。
 case "$verb" の場合
  '作成された')
  # PID ファイルが存在するようになるまで待機します。
  テスト -s "$pid_file_path" && i='' && break
  ;;
  '削除')
  # このPIDファイルが消えるまで待つ
  テスト! -s "$pid_file_path" && i='' && break
  ;;
  *)
  echo "wait_for_pid () の使用法: wait_for_pid が作成されました| pid pid_file_path が削除されました"
  出口1
  ;;
 エサック
 # サーバーが稼働していない場合、pid ファイルは更新されません
 テスト -n "$pid"; の場合
  kill -0 "$pid" 2>/dev/null;の場合
  : # サーバーはまだ稼働しています
  それ以外
  # 最後の pid ファイル チェックと現在の間にサーバーが終了した可能性があります。 
  テスト -n "$avoid_race_condition"; の場合
   競合状態を回避する=""
   続行 # もう一度確認してください。
  フィ
  # ファイルに影響を与えるものは何もありません。
  log_failure_msg "サーバーは PID ファイル ($pid_file_path) を更新せずに終了しました。"
  return 1 # これ以上待機しません。
  フィ
 フィ
 エコー $echo_n ".$echo_c"
 i=`式 $i + 1`
 睡眠1
 終わり
 テスト -z "$i" の場合;
 ログ成功メッセージ
 0を返す
 それ以外
 ログ失敗メッセージ
 戻り値 1
 フィ
}

サービススクリプト停止オプション

まず、pid ファイルの長さがゼロでないかどうかを確認します。

-s ファイル ファイルの長さがゼロでない場合は真

この時点で、mysqld プロセスの pid は pid ファイルを通じて取得されます。これは mysqld_safe プロセスの pid ではないことに注意してください。

次に、mysqld プロセスが正常に実行されているかどうかを確認します。

はいの場合は、$mysqld_pidを強制終了してmysqldプロセスをシャットダウンします。

プロセスを強制終了する最も安全な方法は、修飾子やフラグなしで、単に kill コマンドを使用することです。

標準の kill コマンドは通常、問題のあるプロセスを終了し、プロセスのリソースをシステムに解放します。ただし、プロセスが子プロセスを開始した場合、親プロセスを終了するだけでは子プロセスは実行されたままになり、リソースが消費され続けます。これらのいわゆる「ゾンビ プロセス」を防ぐには、親プロセスを強制終了する前に、その子プロセスをすべて強制終了するようにしてください。

次に、wait_for_pid 関数を呼び出して判断します。実は、wait_for_pid 関数で Avoid_race_condition 変数を設定する目的は、停止オプションのためです。確かに、pid ファイルをチェックした後、プロセスが生きているかどうかを確認する前に、mysqld が終了する可能性があります。

mysqld プロセスが正常に実行されていない場合は、「MySQL サーバー プロセス #$mysqld_pid が実行されていません!」というメッセージが出力され、pid ファイルが削除されます。

stop を実行したときに pid ファイルの長さが 0 の場合、「MySQL サーバーの PID ファイルが見つかりません」というメッセージが出力されます。

したがって、pid ファイルが存在しない場合は、サービス スクリプトから停止オプションを実行しても、mysqld プロセスはシャットダウンされません。この場合、$mysqld_pid を強制終了することで、mysqld プロセスをシャットダウンできます。

'停止')
 # デーモンを停止します。ここでは、
 # ルートパスワード。
 テスト -s "$mysqld_pid_file_path" の場合
 それから
  mysqld_pid=`cat "$mysqld_pid_file_path"`
  (kill -0 $mysqld_pid 2>/dev/null)の場合
  それから
  echo $echo_n "MySQL をシャットダウンしています"
  $mysqld_pid を強制終了する
  # mysqld は終了時に pid ファイルを削除するはずなので、それを待ちます。
  wait_for_pid が "$mysqld_pid" "$mysqld_pid_file_path" を削除しました。 return_value=$?
  それ以外
  log_failure_msg "MySQL サーバー プロセス #$mysqld_pid が実行されていません!"
  rm "$mysqld_pid_file_path"
  フィ
  # RedHat / SuSE のロックを削除
  テスト -f "$lock_file_path"
  それから
  rm -f "$lock_file_path"
  フィ
  終了 $return_value
 それ以外
  log_failure_msg "MySQL サーバーの PID ファイルが見つかりませんでした!"
 フィ
 ;;

サービススクリプトの再起動オプション

まず、停止操作を実行します。停止操作が成功した場合は、開始操作の実行を続行します。

停止操作が失敗した場合、「実行中のサーバーの停止に失敗したため、起動を試行しません。」というメッセージが出力され、スクリプトは終了します。

 '再起動')
 # サービスを停止し、
 # 実行中かどうかにかかわらず、もう一度起動してください。
 $0の場合は$other_argsを停止します。
  $0 開始 $other_args
 それ以外
  log_failure_msg 「実行中のサーバーを停止できなかったため、起動を試行しません。」
  出口1
 フィ
 ;;

サービススクリプトの再読み込みオプション

まず、pid ファイルの長さが 0 かどうかを判断します。そうでない場合は、ファイル内の値を mysqld_pid 変数の値に設定します。

次に、プロセスに対して kill -HUP 操作を実行します。

キル -HUP pid

pid はプロセス ID です。サービスを停止して再起動せずに設定を変更する場合は、このコマンドを使用します。構成ファイルに必要な変更を加えた後、このコマンドを発行してサービス構成を動的に更新します。

慣例により、ハングアップ信号 (シグナル 1 または HUP) を送信すると、ほとんどのサーバー プロセス (すべての通常のプロセス) がリセットされ、構成ファイルが再ロードされます。

pid ファイルの長さが 0 の場合、「MySQL PID ファイルが見つかりません!」が出力されます。

 'リロード'|'強制リロード')
 テスト -s "$mysqld_pid_file_path" の場合、
  mysqld_pid を読み取り < "$mysqld_pid_file_path"
  kill -HUP $mysqld_pid && log_success_msg "MySQL サービスを再ロードしています"
  "$mysqld_pid_file_path" をタッチします
 それ以外
  log_failure_msg "MySQL PID ファイルが見つかりませんでした!"
  出口1
 フィ
 ;;

サービススクリプトステータスオプション

まず、pid ファイルの長さが 0 かどうかを判断します。そうでない場合は、ファイル内の値を読み取り、pid に対応するプロセスが正常に実行されているかどうかを判断します。

正常に実行されると、「MySQL running」と出力されます。

正常でない場合は、「MySQL は実行されていませんが、PID ファイルは存在します」という出力が表示されます。

pid ファイルの長さが 0 の場合は、mysqld 起動コマンドを使用して pid を取得してみてください。

このとき、複数のインスタンスを起動する mysqld プログラムが存在する可能性があり、その結果、pid_count=`echo $mysqld_pid | wc -w` が 1 より大きくなります。

このとき、「複数の MySQL が実行中ですが、PID ファイルが見つかりませんでした」というメッセージが出力され、スクリプトは終了します。

mysqld_pidが空の場合、引き続き「$lock_file_path」が存在するかどうかを確認します。存在する場合は、

「MySQL は実行されていませんが、ロック ファイル ($lock_file_path) が存在します」というメッセージが出力されます。

「$lock_file_path」が存在しない場合は、「MySQL が実行されていません」というメッセージが出力されます。

mysqld_pid が 1 の場合、「MySQL は実行されていますが、PID ファイルが見つかりません」というメッセージが出力されます。

 '状態')
 # まず、pidファイルが存在するかどうかを確認します
 テスト -s "$mysqld_pid_file_path" の場合、 
  mysqld_pid を読み取り < "$mysqld_pid_file_path"
  kill -0 $mysqld_pid 2>/dev/nullの場合; 
  log_success_msg "MySQL が実行中です ($mysqld_pid)"
  終了 0
  それ以外
  log_failure_msg 「MySQL は実行されていませんが、PID ファイルは存在します」
  出口1
  フィ
 それ以外
  # 適切なmysqldプロセスを探します
  mysqld_pid=`pidof $libexecdir/mysqld`
  # 複数のPIDが存在するかどうかをテストする
  pid_count=`echo $mysqld_pid | wc -w`
  $pid_count -gt 1 をテストする場合、
  log_failure_msg "複数の MySQL が実行中ですが、PID ファイルが見つかりません ($mysqld_pid)"
  出口5
  elif test -z $mysqld_pid; その後 
  テスト -f "$lock_file_path" の場合; 
   log_failure_msg "MySQL は実行されていませんが、ロック ファイル ($lock_file_path) が存在します"
   出口2
  フィ 
  log_failure_msg 「MySQL が実行されていません」
  出口3
  それ以外
  log_failure_msg 「MySQL は実行されていますが、PID ファイルが見つかりませんでした」
  出口4
  フィ
 フィ
 ;;

サービススクリプトのその他のオプション

スクリプトの最初の引数が上記のオプションのいずれでもない場合は、使用方法情報が出力されます。

 *)
  # 使用法
  ベース名=`ベース名 "$0"`
  echo "使用方法: $basename {start|stop|restart|reload|force-reload|status} [ MySQL サーバー オプション ]"
  出口1
 ;;

この時点で、mysqlサービススクリプトの解析は完了です〜

要約する

サービススクリプトからMySQLを起動すると、「サーバーはPIDファイルを更新せずに終了しました」というエラーが報告されます。2つの条件があります。

まず、pidファイルが存在しない

次に、kill -0 $pidを実行してプロセスが存在しないことを確認します。

現時点では、エラーは MySQL データベースのエラー ログを通じてのみ見つけることができます。

サービススクリプトが調整されていない場合、デフォルトのベースディレクトリは /usr/local/mysql で、データディレクトリは /usr/local/mysql/data です。

MySQLサービスがデフォルトのパスにない場合は、

スクリプトで明示的に設定する必要があります

テスト後、次の設定が必要です。

1. basedirを設定し、conf変数を追加する

ここで、conf は mysqld の設定ファイルを指します。設定ファイルでは basedir と datadir の値を明示的に指定することをお勧めします。

ここで、datadir は設定ファイルを通じて取得できるため、datadir を設定する必要はありません。

しかし、my_print_deefautsコマンドはまずbasedirに従って判断される必要があるため、basedirを指定する必要があります。

ベースディレクトリ=/usr/local/mysql-advanced-5.6.23-linux-glibc2.5-x86_64
データディレクトリ=
conf=/usr/local/mysql-advanced-5.6.23-linux-glibc2.5-x86_64/my_3308.cnf

2. 256行目にextra_args=" -c $conf"を追加します。

extra_args=" -e $basedir/my.cnf.bak"
テスト -r "$basedir/my.cnf"
それから
 extra_args="-e $basedir/my.cnf"
それ以外
 テスト -r "$datadir/my.cnf"
 それから
 extra_args="-e $datadir/my.cnf"
 フィ
フィ
extra_args=" -c $conf"

3. 285行目のmysqld_safeの起動パラメータを変更する

意思

 $bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &

変更後、

  $bindir/mysqld_safe --defaults-file="$conf" --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 &

主に--defaults-fileオプションを追加しました

上記は、MySQL の起動時に「サーバーは PID ファイルを更新せずに終了しました」というエラーが表示される理由の詳細な分析です。お役に立てば幸いです。ご質問がある場合は、メッセージを残してください。すぐに返信いたします。また、123WORDPRESS.COM ウェブサイトをサポートしてくださっている皆様にも感謝申し上げます。

以下もご興味があるかもしれません:
  • インターフェイス実装サンプルコード付き Python チャット ルーム (tkinter、Mysql、Treading、ソケット)
  • エラー 2002 (HY000): ソケット ''/tmp/mysql.sock'' を介してローカル MySQL サーバーに接続できません
  • ソケット ''/tmp/mysql.sock'' 経由でローカル MySQL に接続できない解決策
  • LAN チャット ルームを構築するための Java+jdbc+mysql+socket
  • シンプルなファイルアップローダーコードを実装するためのJava Socket+mysql
  • mysqlソケットファイルの機能の詳細な説明
  • MySQL エラー ERROR 2002 (HY000): ソケット経由でローカル MySQL サーバーに接続できません
  • MySQL HandlerSocket プラグインのインストールと設定のチュートリアル
  • PID を作成できないために MySQL が起動できない問題を解決する方法
  • MySQL 起動エラー MySQL サーバーの PID ファイルが見つかりませんでした
  • Mysql がクラッシュして再起動できない後に pid ファイルが見つからない問題の解決方法
  • MySQL PIDファイル損失関連エラーの解決策
  • mysql: サーバーを起動できません: PID ファイルを作成できません: デバイスに空き容量がありません
  • MySQL のヒント: PID ファイルを更新せずにサーバーが終了する問題の解決方法
  • Linux mysql エラー: MYSQL: サーバーは PID ファイルを更新せずに終了しました
  • MySQL を起動するための解決策。pid ファイルのマネージャーがファイルを更新せずに終了しました。[失敗]
  • MySQL の pid とソケットの詳細な説明

<<:  WeChatアプレットでQRコードを識別するために長押しする実装プロセス

>>:  Ubuntuで余分なカーネルを削除する方法

推薦する

JavaScriptを使って動的にテーブルを生成するケースの詳しい説明

目次序文実装のアイデア実装コード成果を達成する序文これは、テーブルを動的に追加する例です。[追加] ...

Linux での MySQL 8.0 インストール チュートリアル

この記事では、LinuxでMySQL 8.0をインストールする方法を紹介します。具体的な内容は次のと...

インターフェーステストプラットフォームを構築するためのDjango+Vue+Dockerの詳細な説明

1. 冒頭の2つの単語みなさんこんにちは。私の名前はLin Zonglinです。私はテストエンジニア...

Linux がますます人気になっている 10 の理由

Linux はますます多くのユーザーに愛されてきました。なぜ Linux はこれほど急速に発展し、い...

Nginx ロケーション設定のチュートリアル (ゼロから)

基礎位置の一致順序は、「最初に正規表現に一致し、次に共通表現に一致」です。実際のロケーションの一致順...

MySQL累積計算実装方法の詳しい説明

目次序文需要分析MySQL ユーザー変数累積計算にMysqlユーザー変数を使用する要約するこの記事で...

知っておくべき JS 配列削減の高度な使い方 25 選

序文Reduce は ES5 で追加された新しい従来の配列メソッドの 1 つです。forEach、f...

JavaScript で 24 以上の配列メソッドを手動で実装する

目次1. トラバーサルクラス1. 各2. 地図3. すべての4. いくつか5. フィルター6. 減ら...

React refsの詳細な紹介

1. 何ですかRefs 、コンピューターでは Resilient File System (ReF...

HTML テーブル データを Json 形式に変換するサンプル コード

<table>テーブルデータをJSON形式に変換するJavaScript関数は次のとおり...

Linux dirnameコマンドの具体的な使い方

01. コマンドの概要dirname - ファイル名からディレクトリ以外のサフィックスを削除しますd...

webpackでCSSを分割・圧縮し、リンクでインポートする手順

まずコードファイルの構造を見てみましょう。エントリファイル (index1.js) の内容: ...

Vue はユーザーのログイン状態を維持します (さまざまなトークン保存方法)

目次クッキーの設定方法クッキーのデメリット: LocalStorage と SessionStora...

CentOS 6 ZLMediaKit のコンパイルとインストール分析

Centos6にZLMediaKitをインストールするZLMediaKit の作者は Ubuntu ...

dockerコンテナがIP経由でホストマシンにアクセスできない問題を解決する方法の詳細な説明

問題の起源docker を使用する場合、残念ながら docker コンテナ内のホストのポート 80 ...