ops: load MySQL diagnostics credentials from env

This commit is contained in:
yml2213
2026-08-30 16:22:04 +08:00
parent 174f931486
commit a45d7597fb
+55 -5
View File
@@ -8,16 +8,60 @@ set -Eeuo pipefail
# #
# 可覆盖的环境变量: # 可覆盖的环境变量:
# PG_SERVICE=postgres PG_USER=postgres PG_DB=order_site # PG_SERVICE=postgres PG_USER=postgres PG_DB=order_site
# MYSQL_CONTAINER=douyu-login-db MYSQL_USER=root MYSQL_PASSWORD=... # ENV_FILE=/root/douyu_login_py/.env
# MYSQL_CONTAINER=douyu-login-db MYSQL_DIAGNOSTIC_USER=root MYSQL_PASSWORD=...
#
# 未显式传入密码时,会从 ENV_FILE 读取 MYSQL_ROOT_PASSWORDroot)或
# MYSQL_PASSWORD(非 root)。脚本不会把密码写入诊断文件。
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUTPUT_FILE="${1:-${PROJECT_ROOT}/order-site-diagnostics-$(date +%Y%m%d-%H%M%S).txt}" OUTPUT_FILE="${1:-${PROJECT_ROOT}/order-site-diagnostics-$(date +%Y%m%d-%H%M%S).txt}"
# 生产环境的 MySQL 通常由独立的 douyu_login_py Compose 项目管理。
# 自动寻找包含 MySQL 密码配置的 .env,也允许用 ENV_FILE 指定其他路径。
ENV_FILE="${ENV_FILE:-}"
if [[ -z "${ENV_FILE}" ]]; then
for candidate in \
"${PROJECT_ROOT}/.env" \
"${PROJECT_ROOT}/../douyu_login_py/.env" \
"/root/douyu_login_py/.env"; do
if [[ -f "${candidate}" ]] && grep -qE '^[[:space:]]*MYSQL_(ROOT_)?PASSWORD=' "${candidate}"; then
ENV_FILE="${candidate}"
break
fi
done
fi
# 显式环境变量优先于 .env,避免服务器临时指定的诊断目标被覆盖。
EXPLICIT_MYSQL_CONTAINER="${MYSQL_CONTAINER:-}"
EXPLICIT_MYSQL_USER="${MYSQL_USER:-}"
EXPLICIT_MYSQL_PASSWORD="${MYSQL_PASSWORD:-}"
if [[ -n "${ENV_FILE}" && -f "${ENV_FILE}" ]]; then
set -a
# shellcheck disable=SC1090
. "${ENV_FILE}"
set +a
fi
if [[ -n "${EXPLICIT_MYSQL_CONTAINER}" ]]; then MYSQL_CONTAINER="${EXPLICIT_MYSQL_CONTAINER}"; fi
if [[ -n "${EXPLICIT_MYSQL_PASSWORD}" ]]; then MYSQL_PASSWORD="${EXPLICIT_MYSQL_PASSWORD}"; fi
PG_SERVICE="${PG_SERVICE:-postgres}" PG_SERVICE="${PG_SERVICE:-postgres}"
PG_USER="${PG_USER:-postgres}" PG_USER="${PG_USER:-postgres}"
PG_DB="${PG_DB:-order_site}" PG_DB="${PG_DB:-order_site}"
MYSQL_CONTAINER="${MYSQL_CONTAINER:-douyu-login-db}" MYSQL_CONTAINER="${MYSQL_CONTAINER:-douyu-login-db}"
MYSQL_USER="${MYSQL_USER:-root}" if [[ -n "${EXPLICIT_MYSQL_USER}" ]]; then
MYSQL_PASSWORD="${MYSQL_PASSWORD:-}" MYSQL_USER="${EXPLICIT_MYSQL_USER}"
else
# douyu_login_py/.env 的 MYSQL_USER 是应用账号;诊断默认需要 root
# 才能读取 PROCESSLIST、InnoDB 状态和全局性能计数器。
MYSQL_USER="${MYSQL_DIAGNOSTIC_USER:-root}"
fi
if [[ -z "${EXPLICIT_MYSQL_PASSWORD}" && "${MYSQL_USER}" == "root" && -n "${MYSQL_ROOT_PASSWORD:-}" ]]; then
MYSQL_PASSWORD="${MYSQL_ROOT_PASSWORD}"
else
MYSQL_PASSWORD="${MYSQL_PASSWORD:-}"
fi
mkdir -p "$(dirname "${OUTPUT_FILE}")" mkdir -p "$(dirname "${OUTPUT_FILE}")"
: >"${OUTPUT_FILE}" : >"${OUTPUT_FILE}"
@@ -88,6 +132,10 @@ run_mysql_sql() {
fi fi
} }
write_header "diagnostic configuration"
printf 'env_file=%s\nmysql_container=%s\nmysql_user=%s\n' \
"${ENV_FILE:-<none>}" "${MYSQL_CONTAINER}" "${MYSQL_USER}" >>"${OUTPUT_FILE}"
run_cmd "metadata" date -Is run_cmd "metadata" date -Is
run_cmd "host" uname -a run_cmd "host" uname -a
run_cmd "uptime" uptime run_cmd "uptime" uptime
@@ -120,13 +168,15 @@ run_pg_sql "retention table counts" \
"SELECT c.relname AS table_name, c.reltuples::bigint AS estimated_rows, pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relname IN ('orders','kuaishou_industry_vouchers','task_events','webhook_events','admin_audit_logs','work_order_events') ORDER BY pg_total_relation_size(c.oid) DESC;" "SELECT c.relname AS table_name, c.reltuples::bigint AS estimated_rows, pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relname IN ('orders','kuaishou_industry_vouchers','task_events','webhook_events','admin_audit_logs','work_order_events') ORDER BY pg_total_relation_size(c.oid) DESC;"
run_mysql_sql "server status" \ run_mysql_sql "server status" \
"SELECT VERSION() AS version, @@hostname AS hostname, @@max_connections AS max_connections, @@innodb_buffer_pool_size AS innodb_buffer_pool_size, @@innodb_flush_log_at_trx_commit AS flush_log_at_trx_commit, @@sync_binlog AS sync_binlog;" "SELECT VERSION() AS version, @@hostname AS hostname, @@max_connections AS max_connections, @@innodb_buffer_pool_size AS innodb_buffer_pool_size, @@innodb_flush_log_at_trx_commit AS flush_log_at_trx_commit, @@sync_binlog AS sync_binlog, @@performance_schema AS performance_schema, @@slow_query_log AS slow_query_log, @@long_query_time AS long_query_time;"
run_mysql_sql "process list" "SHOW FULL PROCESSLIST;" run_mysql_sql "process list" "SHOW FULL PROCESSLIST;"
run_mysql_sql "innodb status" "SHOW ENGINE INNODB STATUS;" run_mysql_sql "innodb status" "SHOW ENGINE INNODB STATUS;"
run_mysql_sql "largest tables" \ run_mysql_sql "largest tables" \
"SELECT table_schema, table_name, engine, table_rows, ROUND((data_length+index_length)/1024/1024,2) AS total_mb, ROUND(data_length/1024/1024,2) AS data_mb, ROUND(index_length/1024/1024,2) AS index_mb FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','performance_schema','mysql','sys') ORDER BY data_length+index_length DESC LIMIT 30;" "SELECT table_schema, table_name, engine, table_rows, ROUND((data_length+index_length)/1024/1024,2) AS total_mb, ROUND(data_length/1024/1024,2) AS data_mb, ROUND(index_length/1024/1024,2) AS index_mb FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','performance_schema','mysql','sys') ORDER BY data_length+index_length DESC LIMIT 30;"
run_mysql_sql "innodb counters" \ run_mysql_sql "innodb counters" \
"SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected','Threads_running','Created_tmp_tables','Created_tmp_disk_tables','Innodb_buffer_pool_reads','Innodb_buffer_pool_read_requests','Innodb_buffer_pool_pages_dirty','Innodb_log_waits','Innodb_row_lock_waits','Innodb_row_lock_time','Innodb_data_reads','Innodb_data_writes','Innodb_os_log_fsyncs');" "SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected','Threads_running','Max_used_connections','Threads_created','Aborted_connects','Created_tmp_tables','Created_tmp_disk_tables','Com_commit','Com_rollback','Innodb_buffer_pool_reads','Innodb_buffer_pool_read_requests','Innodb_buffer_pool_pages_dirty','Innodb_buffer_pool_wait_free','Innodb_log_waits','Innodb_log_writes','Innodb_os_log_fsyncs','Innodb_os_log_pending_fsyncs','Innodb_row_lock_waits','Innodb_row_lock_current_waits','Innodb_row_lock_time','Innodb_data_reads','Innodb_data_writes');"
run_mysql_sql "statement digest" \
"SELECT SCHEMA_NAME, DIGEST_TEXT, COUNT_STAR, ROUND(SUM_TIMER_WAIT/1000000000000,2) AS total_seconds, ROUND(AVG_TIMER_WAIT/1000000000,2) AS mean_ms, SUM_ROWS_EXAMINED, SUM_ROWS_SENT, SUM_NO_INDEX_USED, SUM_NO_GOOD_INDEX_USED FROM performance_schema.events_statements_summary_by_digest WHERE SCHEMA_NAME IS NOT NULL ORDER BY SUM_TIMER_WAIT DESC LIMIT 30;"
write_header "next step" write_header "next step"
cat >>"${OUTPUT_FILE}" <<'EOF' cat >>"${OUTPUT_FILE}" <<'EOF'