外观
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: 管理大量故障处理脚本的方法:
- 分类管理脚本,建立清晰的目录结构
- 使用版本控制系统管理脚本
- 为脚本编写详细的文档
- 实现脚本的自动化部署和更新
- 建立脚本的测试和验证机制
