Skip to content

TDSQL 故障处理脚本

性能诊断脚本

1. 慢查询分析脚本

bash
#!/bin/bash

# 脚本名称:tdsql_slow_query_analyzer.sh
# 功能:分析TDSQL慢查询日志
# 版本:v1.0.0
# 日期:2023-01-01
# 作者:数据库运维组

# 设置严格模式
set -euo pipefail

# 定义变量
SLOW_LOG_FILE="/var/log/mysql/slow.log"
ANALYSIS_RESULT="/tmp/slow_query_analysis_$(date +"%Y%m%d_%H%M%S").txt"
TOP_N=20

# 检查慢查询日志是否存在
if [ ! -f "$SLOW_LOG_FILE" ]; then
    echo "错误:慢查询日志文件不存在: $SLOW_LOG_FILE"
    exit 1
fi

# 分析慢查询日志
echo "=== TDSQL 慢查询分析报告 ===" > "$ANALYSIS_RESULT"
echo "分析时间: $(date)" >> "$ANALYSIS_RESULT"
echo "慢查询日志: $SLOW_LOG_FILE" >> "$ANALYSIS_RESULT"
echo "=============================" >> "$ANALYSIS_RESULT"
echo >> "$ANALYSIS_RESULT"

# 1. 慢查询总数
echo "1. 慢查询总数: $(grep -c "Query_time:" "$SLOW_LOG_FILE")" >> "$ANALYSIS_RESULT"

# 2. 平均查询时间
echo -n "2. 平均查询时间: " >> "$ANALYSIS_RESULT"
grep "Query_time:" "$SLOW_LOG_FILE" | awk -F "Query_time:" '{print $2}' | awk '{sum+=$1} END {print sum/NR " 秒"}' >> "$ANALYSIS_RESULT"

# 3. 最长查询时间
echo -n "3. 最长查询时间: " >> "$ANALYSIS_RESULT"
grep "Query_time:" "$SLOW_LOG_FILE" | awk -F "Query_time:" '{print $2}' | sort -nr | head -1 >> "$ANALYSIS_RESULT"

# 4. TOP $TOP_N 慢查询
echo -e "\n4. TOP $TOP_N 慢查询(按执行时间):" >> "$ANALYSIS_RESULT"
grep -A 10 "Query_time:" "$SLOW_LOG_FILE" | grep -B 10 -A 10 "Query_time:" | 
awk '/Query_time:/ {print $0; getline; getline; print "   "$0; print "---"}' | 
sort -nr -k3 | head -$((TOP_N*4)) >> "$ANALYSIS_RESULT"

# 5. 慢查询时间分布
echo -e "\n5. 慢查询时间分布:" >> "$ANALYSIS_RESULT"
echo "   0-1秒: $(grep "Query_time:" "$SLOW_LOG_FILE" | awk -F "Query_time:" '{if ($2 >=0 && $2 <1) print $0}' | wc -l)" >> "$ANALYSIS_RESULT"
echo "   1-5秒: $(grep "Query_time:" "$SLOW_LOG_FILE" | awk -F "Query_time:" '{if ($2 >=1 && $2 <5) print $0}' | wc -l)" >> "$ANALYSIS_RESULT"
echo "   5-10秒: $(grep "Query_time:" "$SLOW_LOG_FILE" | awk -F "Query_time:" '{if ($2 >=5 && $2 <10) print $0}' | wc -l)" >> "$ANALYSIS_RESULT"
echo "   10秒以上: $(grep "Query_time:" "$SLOW_LOG_FILE" | awk -F "Query_time:" '{if ($2 >=10) print $0}' | wc -l)" >> "$ANALYSIS_RESULT"

# 6. 慢查询发生时间分布
echo -e "\n6. 慢查询发生时间分布:" >> "$ANALYSIS_RESULT"
grep "Query_time:" "$SLOW_LOG_FILE" | awk '{print $1}' | cut -d":" -f1 | sort | uniq -c | sort -nr >> "$ANALYSIS_RESULT"

echo -e "\n分析报告已生成: $ANALYSIS_RESULT" >> "$ANALYSIS_RESULT"
echo -e "\n=============================" >> "$ANALYSIS_RESULT"

echo "慢查询分析完成,报告生成在: $ANALYSIS_RESULT"

2. 索引使用分析脚本

python
#!/usr/bin/env python3

# 脚本名称:tdsql_index_analyzer.py
# 功能:分析TDSQL索引使用情况
# 版本:v1.0.0
# 日期:2023-01-01
# 作者:数据库运维组

import sys
import pymysql
import argparse
from datetime import datetime

# 解析参数
parser = argparse.ArgumentParser(description='TDSQL索引使用分析脚本')
parser.add_argument('--host', type=str, default='localhost', help='数据库主机')
parser.add_argument('--port', type=int, default=3306, help='数据库端口')
parser.add_argument('--user', type=str, required=True, help='数据库用户名')
parser.add_argument('--password', type=str, required=True, help='数据库密码')
parser.add_argument('--database', type=str, required=True, help='数据库名称')
parser.add_argument('--output', type=str, default='index_analysis.txt', help='输出文件名')
args = parser.parse_args()

# 连接数据库
try:
    conn = pymysql.connect(
        host=args.host,
        port=args.port,
        user=args.user,
        password=args.password,
        database=args.database,
        charset='utf8mb4'
    )
    cursor = conn.cursor()
except Exception as e:
    print(f"连接数据库失败: {str(e)}")
    sys.exit(1)

# 分析索引使用情况
def analyze_index_usage():
    # 获取所有表
    cursor.execute("SHOW TABLES")
    tables = cursor.fetchall()
    
    with open(args.output, 'w') as f:
        f.write("=== TDSQL 索引使用分析报告 ===\n")
        f.write(f"分析时间: {datetime.now()}\n")
        f.write(f"数据库: {args.database}\n")
        f.write("=============================\n\n")
        
        for table in tables:
            table_name = table[0]
            f.write(f"表名: {table_name}\n")
            f.write("-" * 50 + "\n")
            
            # 获取表的索引信息
            cursor.execute(f"SHOW INDEX FROM {table_name}")
            indexes = cursor.fetchall()
            
            if not indexes:
                f.write("  无索引\n\n")
                continue
            
            # 显示索引信息
            for idx in indexes:
                f.write(f"  索引名: {idx[2]}\n")
                f.write(f"  列名: {idx[4]}\n")
                f.write(f"  唯一: {'是' if idx[1] == 0 else '否'}\n")
                f.write(f"  基数: {idx[6]}\n")
                f.write("  ---\n")
            
            f.write("\n")
    
    print(f"索引分析完成,报告生成在: {args.output}")

# 执行分析
if __name__ == "__main__":
    analyze_index_usage()
    cursor.close()
    conn.close()

故障检测脚本

1. 实例状态检测脚本

bash
#!/bin/bash

# 脚本名称:tdsql_instance_checker.sh
# 功能:检测TDSQL实例状态
# 版本:v1.0.0
# 日期:2023-01-01
# 作者:数据库运维组

# 设置严格模式
set -euo pipefail

# 定义变量
MYSQL_USER="root"
MYSQL_PASSWORD="password"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
LOG_FILE="/var/log/tdsql_instance_check.log"
ALARM_SCRIPT="/scripts/send_alarm.sh"

# 日志函数
log() {
    echo "$(date +"%Y-%m-%d %H:%M:%S") - $1" >> "$LOG_FILE"
}

# 检查实例状态
check_instance_status() {
    log "开始检查TDSQL实例状态: $MYSQL_HOST:$MYSQL_PORT"
    
    # 检查MySQL是否可连接
    if ! mysqladmin -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" ping > /dev/null 2>&1; then
        log "错误:实例不可连接"
        $ALARM_SCRIPT "TDSQL实例不可连接: $MYSQL_HOST:$MYSQL_PORT" "严重"
        return 1
    fi
    
    # 检查实例状态
    status=$(mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SELECT @@global.read_only" -sN)
    if [ "$status" = "1" ]; then
        log "警告:实例处于只读模式"
        $ALARM_SCRIPT "TDSQL实例处于只读模式: $MYSQL_HOST:$MYSQL_PORT" "警告"
    fi
    
    # 检查连接数
    connections=$(mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'" -sN | awk '{print $2}')
    max_connections=$(mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW GLOBAL VARIABLES LIKE 'max_connections'" -sN | awk '{print $2}')
    
    connection_percent=$((connections * 100 / max_connections))
    if [ "$connection_percent" -gt 90 ]; then
        log "警告:连接数过高 ($connections/$max_connections, $connection_percent%)"
        $ALARM_SCRIPT "TDSQL实例连接数过高: $connections/$max_connections" "警告"
    fi
    
    # 检查慢查询数
    slow_queries=$(mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW GLOBAL STATUS LIKE 'Slow_queries'" -sN | awk '{print $2}')
    if [ "$slow_queries" -gt 100 ]; then
        log "警告:慢查询数过高 ($slow_queries)"
        $ALARM_SCRIPT "TDSQL实例慢查询数过高: $slow_queries" "警告"
    fi
    
    log "实例状态检查完成,状态正常"
    return 0
}

# 主函数
check_instance_status
exit $?

2. 主从复制检测脚本

bash
#!/bin/bash

# 脚本名称:tdsql_replication_checker.sh
# 功能:检测TDSQL主从复制状态
# 版本:v1.0.0
# 日期:2023-01-01
# 作者:数据库运维组

# 设置严格模式
set -euo pipefail

# 定义变量
MYSQL_USER="root"
MYSQL_PASSWORD="password"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
LOG_FILE="/var/log/tdsql_replication_check.log"
ALARM_SCRIPT="/scripts/send_alarm.sh"
MAX_DELAY=30  # 最大延迟(秒)

# 日志函数
log() {
    echo "$(date +"%Y-%m-%d %H:%M:%S") - $1" >> "$LOG_FILE"
}

# 检查主从复制状态
check_replication_status() {
    log "开始检查主从复制状态: $MYSQL_HOST:$MYSQL_PORT"
    
    # 获取主从复制状态
    slave_status=$(mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW SLAVE STATUS\G" -sN)
    
    if [ -z "$slave_status" ]; then
        log "警告:不是从库"
        return 0
    fi
    
    # 解析复制状态
    slave_io_running=$(echo "$slave_status" | grep -i "slave_io_running:" | awk '{print $2}')
    slave_sql_running=$(echo "$slave_status" | grep -i "slave_sql_running:" | awk '{print $2}')
    seconds_behind_master=$(echo "$slave_status" | grep -i "seconds_behind_master:" | awk '{print $2}')
    last_error=$(echo "$slave_status" | grep -i "last_error:" | awk -F: '{print substr($0, index($0,$2))}')
    
    # 检查IO线程状态
    if [ "$slave_io_running" != "Yes" ]; then
        log "错误:IO线程未运行"
        $ALARM_SCRIPT "TDSQL主从复制IO线程未运行: $MYSQL_HOST:$MYSQL_PORT" "严重"
        return 1
    fi
    
    # 检查SQL线程状态
    if [ "$slave_sql_running" != "Yes" ]; then
        log "错误:SQL线程未运行,错误信息: $last_error"
        $ALARM_SCRIPT "TDSQL主从复制SQL线程未运行: $last_error" "严重"
        return 1
    fi
    
    # 检查复制延迟
    if [ "$seconds_behind_master" -gt "$MAX_DELAY" ]; then
        log "警告:复制延迟过高 ($seconds_behind_master 秒)"
        $ALARM_SCRIPT "TDSQL主从复制延迟过高: $seconds_behind_master 秒" "警告"
        return 1
    fi
    
    log "主从复制状态正常,延迟: $seconds_behind_master 秒"
    return 0
}

# 主函数
check_replication_status
exit $?

自动恢复脚本

1. 主从复制恢复脚本

bash
#!/bin/bash

# 脚本名称:tdsql_replication_recovery.sh
# 功能:自动恢复TDSQL主从复制
# 版本:v1.0.0
# 日期:2023-01-01
# 作者:数据库运维组

# 设置严格模式
set -euo pipefail

# 定义变量
MYSQL_USER="root"
MYSQL_PASSWORD="password"
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
LOG_FILE="/var/log/tdsql_replication_recovery.log"
ALARM_SCRIPT="/scripts/send_alarm.sh"
MASTER_HOST="master.example.com"
MASTER_PORT="3306"
REPLICATION_USER="repl"
REPLICATION_PASSWORD="repl_password"

# 日志函数
log() {
    echo "$(date +"%Y-%m-%d %H:%M:%S") - $1" >> "$LOG_FILE"
}

# 恢复主从复制
recover_replication() {
    log "开始恢复主从复制: $MYSQL_HOST:$MYSQL_PORT -> $MASTER_HOST:$MASTER_PORT"
    
    # 停止复制
    log "停止复制"
    mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "STOP SLAVE" > /dev/null 2>&1 || true
    
    # 重置复制
    log "重置复制"
    mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "RESET SLAVE ALL" > /dev/null 2>&1 || true
    
    # 获取主库状态
    log "获取主库状态"
    master_status=$(mysql -h"$MASTER_HOST" -P"$MASTER_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW MASTER STATUS" -sN)
    
    if [ -z "$master_status" ]; then
        log "错误:获取主库状态失败"
        $ALARM_SCRIPT "TDSQL主从复制恢复失败:无法获取主库状态" "严重"
        return 1
    fi
    
    # 解析主库状态
    master_log_file=$(echo "$master_status" | awk '{print $1}')
    master_log_pos=$(echo "$master_status" | awk '{print $2}')
    
    log "主库日志文件: $master_log_file, 位置: $master_log_pos"
    
    # 重新配置复制
    log "重新配置复制"
    mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e " 
    CHANGE MASTER TO \
    MASTER_HOST='$MASTER_HOST', \
    MASTER_PORT=$MASTER_PORT, \
    MASTER_USER='$REPLICATION_USER', \
    MASTER_PASSWORD='$REPLICATION_PASSWORD', \
    MASTER_LOG_FILE='$master_log_file', \
    MASTER_LOG_POS=$master_log_pos;
    START SLAVE;
    " > /dev/null 2>&1
    
    # 检查恢复结果
    sleep 5
    slave_status=$(mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW SLAVE STATUS\G" -sN)
    
    slave_io_running=$(echo "$slave_status" | grep -i "slave_io_running:" | awk '{print $2}')
    slave_sql_running=$(echo "$slave_status" | grep -i "slave_sql_running:" | awk '{print $2}')
    
    if [ "$slave_io_running" = "Yes" ] && [ "$slave_sql_running" = "Yes" ]; then
        log "主从复制恢复成功"
        $ALARM_SCRIPT "TDSQL主从复制已恢复" "恢复"
        return 0
    else
        log "错误:主从复制恢复失败"
        $ALARM_SCRIPT "TDSQL主从复制恢复失败" "严重"
        return 1
    fi
}

# 主函数
recover_replication
exit $?

脚本管理与最佳实践

1. 脚本部署

  • 集中管理:将所有脚本集中存储在专用目录,如 /scripts/tdsql/
  • 版本控制:使用Git等版本控制系统管理脚本
  • 权限设置:脚本权限设置为700,只允许运维用户执行
  • 配置分离:将配置信息与脚本分离,使用配置文件或环境变量
  • 自动化部署:使用Ansible等工具自动化部署脚本

2. 脚本执行

  • 定时执行:使用cron定时执行检测脚本
  • 按需执行:手动执行恢复脚本
  • 事件触发:根据监控告警自动触发脚本
  • 并行控制:避免脚本并行执行导致冲突
  • 超时控制:为脚本设置合理的超时时间

3. 日志管理

  • 集中日志:所有脚本日志集中存储
  • 日志轮换:配置日志轮换,避免日志过大
  • 日志分析:定期分析脚本日志,优化脚本
  • 日志告警:重要日志事件触发告警

4. 安全管理

  • 最小权限:脚本执行使用最小权限用户
  • 密码保护:避免脚本中硬编码密码,使用加密存储或密钥管理系统
  • 审计日志:记录脚本执行的详细审计日志
  • 访问控制:限制脚本的访问和执行权限

常见问题(FAQ)

Q1: 如何确保故障处理脚本的安全性?

A1: 确保故障处理脚本安全性的方法:

  • 使用最小权限用户执行脚本
  • 避免硬编码密码和敏感信息
  • 脚本权限设置为700,只允许授权用户执行
  • 对脚本进行代码审查
  • 记录详细的审计日志
  • 定期检查脚本的完整性

Q2: 如何避免脚本执行对生产环境造成影响?

A2: 避免脚本影响生产环境的方法:

  • 在测试环境充分测试脚本
  • 为脚本设置合理的执行时间窗口
  • 限制脚本的资源使用
  • 为脚本设置超时时间
  • 实现脚本的回滚机制
  • 监控脚本执行过程

Q3: 如何自动化执行故障处理脚本?

A3: 自动化执行故障处理脚本的方法:

  • 使用cron定时执行检测脚本
  • 与监控系统集成,根据告警自动触发脚本
  • 使用自动化运维平台(如Ansible、SaltStack)管理脚本执行
  • 实现事件驱动的脚本执行机制

Q4: 如何设计脚本的回滚机制?

A4: 设计脚本回滚机制的方法:

  • 在执行关键操作前,备份相关配置和数据
  • 记录操作前的状态,便于恢复
  • 实现撤销操作的逻辑
  • 测试回滚机制的有效性
  • 建立回滚操作的触发条件

Q5: 如何管理大量的故障处理脚本?

A5: 管理大量故障处理脚本的方法:

  • 分类管理脚本,建立清晰的目录结构
  • 使用版本控制系统管理脚本
  • 为脚本编写详细的文档
  • 实现脚本的自动化部署和更新
  • 建立脚本的测试和验证机制