mysqld_safe 是 MySQL 官方推薦的生產環境啟動腳本,它不僅負責啟動 mysqld,還提供進程守護、日志輪轉、錯誤重啟、權限降級等關鍵功能。本文通過閱讀 5.1 版本源碼,剖析其核心邏輯與 Shell 編程精華。
解析參數 → 定位基目錄/數據目錄 → 讀取 my.cnf ([mysqld],[mysqld_safe])
→ 合併命令行參數 → 初始化日志系統 (文件/_syslog)
→ 權限檢查與降級 (--user) → 環境準備 (socket目錄、core文件、ulimit)
→ 構建 mysqld 啟動命令 → 進程守護循環 (啟動 → 監控 → 異常重啟 → 清理殭屍進程)
parse_arguments()--defaults-file, --defaults-extra-file, --no-defaults 優先級處理。my_print_defaults 讀取配置文件組 [mysqld], [server], [mysqld_safe], [safe_mysqld] (兼容舊版)。--basedir 指定路徑。$PWD/bin, $PWD/libexec。/usr/local/mysql)。share/mysql/english/errmsg.sys 存在性驗證基目錄合法性。log_generic() 統一入口,支持 init (僅控制台), file (錯誤日志文件), syslog (系統日志)。eval_log_error() 構建管道命令:mysqld ... 2>&1 | logger -t 'mysqld' -p daemon.error 實現 syslog 接入。.err 後綴,避免與 mysqld 寫入同一文件衝突。--user 切換,調用 chown 授權錯誤日志、socket 目錄。ulimit -n 設置打開文件數,ulimit -c 設置 core 文件大小。while true; do
rm -f $socket $pid_file # 清理殘留
eval_log_error "$cmd" # 啟動 mysqld,阻塞等待
if [ ! -f "$pid_file" ]; then break; fi # 正常退出無 pid 文件則跳出
if [ $KILL_MYSQLD -eq 1 ]; then # 殭屍進程清理
ps xaww | grep "$ledir/$MYSQLD>" | grep "pid-file=$pid_file" | ...
kill -9 $zombie_pid
fi
log_notice "mysqld restarted" # 記錄重啟
done
設計亮點:
pid-file 的多個 mysqld 進程,殺殭屍防止端口衝突。trap '' 1 2 3 15 忽略終端中斷信號,防止誤殺守護進程。檢測 nohup nice 是否導致優先級降低 (數值變大),若是則自動提升優先級抵消,確保 mysqld 調度不受啟動方式影響。
| 技巧 | 代碼片段 | 用途 |
|---|---|---|
| 保存/恢復 IFS | save_ifs="${IFS-UNSET}"; IFS=:; ...; IFS="$save_ifs" | 安全分割 PATH |
| sed 轉義特殊字符 | shell_quote_string() { sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g' } | 命令拼接防注入 |
| expr 判斷文件後綴 | expr "$err_log" : '.*\.[^/]*$' | 檢測是否有擴展名 |
| continue 2 跳出雙層循環 | for file; do for dir in $PATH; do ...; continue 2; done; done | 查找命令全路徑 |
| 參數默認值展開 | ${mysql_unix_port:-/tmp/mysql.sock} | 變量兜底 |
[mysqld_safe] 組:log-error, pid-file, user, open-files-limit, nice。systemd 管理時,Type=notify 配合 ExecStart=/usr/bin/mysqld_safe,systemd 接管守護,腳本內循環可關閉 (--skip-kill-mysqld)。mysqld restarted 頻率,頻繁重啟提示硬件/配置問題。