#!/bin/bash # GCP PostgreSQL 自動修復腳本 # 功能:檢測 GCP 資料庫問題,自動 VACUUM、重建索引、恢復連線 # 執行位置:UAT 主機,透過 gcloud SSH 連接 GCP set -e # GCP 配置 GCP_PROJECT="astral-gateway-484913-d7" GCP_ZONE="asia-east1-b" GCP_VM="momo-pro-gcp" NAMESPACE="momo" DB_NAME="momo_analytics" DB_USER="momo" # 通知配置 TELEGRAM_BOT="" TELEGRAM_CHAT="5619078117" LOG_FILE="/var/log/postgres_repair_gcp.log" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [GCP-PG] $1" | tee -a "$LOG_FILE" } send_telegram() { curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT}/sendMessage" \ -d "chat_id=${TELEGRAM_CHAT}" \ -d "parse_mode=HTML" \ -d "text=$1" > /dev/null } # 在 GCP 上執行命令 gcp_exec() { gcloud compute ssh "$GCP_VM" \ --zone="$GCP_ZONE" \ --project="$GCP_PROJECT" \ --command="$1" 2>/dev/null } # 在 GCP Pod 內執行 SQL exec_sql() { gcp_exec "sudo kubectl exec -n $NAMESPACE momo-postgres-0 -- psql -U $DB_USER -d $DB_NAME -t -c \"$1\"" 2>/dev/null } # 檢查資料庫連線 check_connection() { if exec_sql "SELECT 1" | grep -q "1"; then return 0 else return 1 fi } # 檢查死鎖 check_deadlocks() { local deadlocks=$(exec_sql "SELECT count(*) FROM pg_stat_activity WHERE wait_event_type = 'Lock'") echo "$deadlocks" | tr -d ' ' } # 檢查 Dead Tuples (需要 VACUUM) check_dead_tuples() { local dead_tuples=$(exec_sql "SELECT sum(n_dead_tup) FROM pg_stat_user_tables") echo "$dead_tuples" | tr -d ' ' } # 檢查膨脹比例 check_bloat() { local bloat=$(exec_sql " SELECT round(100 * sum(n_dead_tup)::numeric / NULLIF(sum(n_live_tup + n_dead_tup), 0), 2) FROM pg_stat_user_tables ") echo "$bloat" | tr -d ' ' } # 執行 VACUUM ANALYZE do_vacuum() { log "執行 GCP VACUUM ANALYZE..." gcp_exec "sudo kubectl exec -n $NAMESPACE momo-postgres-0 -- psql -U $DB_USER -d $DB_NAME -c 'VACUUM ANALYZE'" 2>/dev/null log "GCP VACUUM ANALYZE 完成" } # 終止長時間查詢 kill_long_queries() { local threshold_minutes=30 log "終止 GCP 超過 ${threshold_minutes} 分鐘的查詢..." local killed=$(exec_sql " SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'active' AND query_start < now() - interval '${threshold_minutes} minutes' AND pid <> pg_backend_pid() " | grep -c "t" || echo "0") log "已終止 $killed 個長時間查詢" echo "$killed" } # 重啟 PostgreSQL Pod restart_postgres() { log "重啟 GCP PostgreSQL Pod..." gcp_exec "sudo kubectl rollout restart statefulset/momo-postgres -n $NAMESPACE" gcp_exec "sudo kubectl rollout status statefulset/momo-postgres -n $NAMESPACE --timeout=180s" log "GCP PostgreSQL 重啟完成" } # 主修復邏輯 main() { log "===== 開始 GCP PostgreSQL 健康檢查 =====" local issues_found=0 local actions_taken="" # 1. 檢查連線 if ! check_connection; then log "錯誤:無法連線到 GCP 資料庫" # 嘗試重啟 restart_postgres sleep 30 if check_connection; then actions_taken="${actions_taken}• 重啟 PostgreSQL Pod\\n" issues_found=1 else send_telegram "🔴 【GCP】PostgreSQL 連線失敗 🏢 環境: 🟥 PROD (momo.wooo.work) ❌ 自動重啟後仍無法連線 📋 需要人工檢查 🔗 SSH: gcloud compute ssh $GCP_VM --zone=$GCP_ZONE ⏰ 時間: $(date '+%Y-%m-%d %H:%M:%S')" exit 1 fi fi # 2. 檢查死鎖 deadlocks=$(check_deadlocks) if [ "${deadlocks:-0}" -gt 0 ]; then log "發現 $deadlocks 個死鎖" killed=$(kill_long_queries) actions_taken="${actions_taken}• 終止 $killed 個死鎖查詢\\n" issues_found=1 fi # 3. 檢查 Dead Tuples dead_tuples=$(check_dead_tuples) if [ "${dead_tuples:-0}" -gt 100000 ]; then log "Dead tuples 過多: $dead_tuples" do_vacuum actions_taken="${actions_taken}• 執行 VACUUM ANALYZE\\n" issues_found=1 fi # 4. 檢查膨脹比例 bloat=$(check_bloat) if [ "$(echo "$bloat > 30" | bc -l 2>/dev/null || echo 0)" -eq 1 ]; then log "表膨脹過高: ${bloat}%" do_vacuum actions_taken="${actions_taken}• 表膨脹 ${bloat}%,已執行 VACUUM\\n" issues_found=1 fi # 發送通知 (如有問題) if [ $issues_found -gt 0 ]; then send_telegram "🔧 【GCP】PostgreSQL 自動維護完成 🏢 環境: 🟥 PROD (momo.wooo.work) 📋 執行動作: ${actions_taken} 📊 目前狀態: • Dead Tuples: ${dead_tuples:-0} • 死鎖數: ${deadlocks:-0} • 膨脹比例: ${bloat:-0}% ✅ 資料庫已恢復正常 ⏰ 時間: $(date '+%Y-%m-%d %H:%M:%S') 🏷️ MOMO Pro 自動修復系統" fi log "===== GCP PostgreSQL 健康檢查完成 =====" } main "$@"