我要提问
ARTICLE DETAIL

资讯详情

前沿编程新知与开发实战干货的深度解读。

MySQL运维自动化:Shell脚本实战与最佳实践

MySQL运维自动化:Shell脚本实战与最佳实践 1. MySQL运维自动化Shell脚本的价值与应用场景作为一名长期奋战在数据库运维一线的工程师我深知日常工作中那些看似简单的重复操作是如何消耗宝贵时间的。每次手动连接服务器、执行查询、记录结果不仅效率低下还容易因疲劳导致误操作。而Shell脚本正是解决这一痛点的利器。Shell脚本在MySQL运维中的核心价值主要体现在三个方面首先它能将重复性操作固化下来避免人工操作的不稳定性其次通过定时任务可以实现7×24小时无人值守监控最后脚本执行过程天然具备可追溯性所有操作都有日志可查。在实际工作中我总结了几个最适合脚本化的高频场景数据库健康检查连接数、慢查询、锁等待等定期数据备份与恢复验证批量修改表结构或数据多实例统一配置管理性能指标采集与分析重要提示生产环境使用脚本时务必遵循最小权限原则像示例中专门创建shell_rw用户的做法就非常值得借鉴。绝对不要为了省事直接使用root账户。2. 环境准备与基础操作2.1 安全配置最佳实践创建专用运维账户时权限分配需要精细控制。以下是改进后的授权方案CREATE USER monitor_user192.168.% IDENTIFIED BY ComplexPwd123!; GRANT SELECT, PROCESS, REPLICATION CLIENT ON *.* TO monitor_user192.168.%; FLUSH PRIVILEGES;这样配置的优势在于限制访问来源IP段192.168.%只授予必要的只读权限包含PROCESS权限用于查看连接信息包含REPLICATION CLIENT用于监控主从状态2.2 测试数据准备进阶技巧创建测试表时建议增加更多真实场景的字段和索引CREATE TABLE products ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL COMMENT 商品名称, category ENUM(电子,食品,服饰) NOT NULL DEFAULT 电子, price DECIMAL(10,2) NOT NULL, stock INT UNSIGNED NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), INDEX idx_category (category), INDEX idx_price (price) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这样的表结构可以模拟更真实的业务场景方便后续测试各种查询和更新操作。3. Shell脚本基础实战3.1 健壮的CRUD脚本实现原始脚本存在密码明文存储的安全隐患改进后的版本#!/bin/bash # 配置文件方式存储敏感信息 CONFIG_FILE/etc/mysql_script.conf if [ ! -f $CONFIG_FILE ]; then echo ❌ 错误: 配置文件 $CONFIG_FILE 不存在 exit 1 fi source $CONFIG_FILE # 检查必要参数 for var in MYSQL_HOST MYSQL_USER MYSQL_PASS MYSQL_DB; do if [ -z ${!var} ]; then echo ❌ 错误: 配置参数 $var 未设置 exit 1 fi done # 使用临时文件存储查询结果 TMP_FILE$(mktemp) # 异常处理函数 cleanup() { [ -f $TMP_FILE ] rm -f $TMP_FILE } trap cleanup EXIT # 执行SQL函数 execute_sql() { local sql$1 local label$2 echo 【$label】执行: $sql mysql -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASS $MYSQL_DB -e $sql $TMP_FILE 21 if [ $? -ne 0 ]; then echo ❌ 执行失败: cat $TMP_FILE return 1 fi echo ✅ 执行结果: cat $TMP_FILE return 0 } # 主流程 execute_sql INSERT INTO products (name, price) VALUES (apple, 10.50) 插入数据 execute_sql SELECT * FROM products WHERE nameapple 查询数据 execute_sql UPDATE products SET price12.5 WHERE nameapple 更新数据 execute_sql DELETE FROM products WHERE nameapple 删除数据改进点包括敏感信息存储在单独配置文件中增加参数检查使用临时文件处理输出完善的错误处理机制函数化重复代码3.2 连接池化技术对于需要频繁连接MySQL的脚本建议使用连接池技术提高性能# 使用mysqlsh实现连接池 #!/bin/bash # 初始化连接 mysqlsh --uri$MYSQL_USER$MYSQL_HOST --password$MYSQL_PASS --schema$MYSQL_DB --js EOF // 执行多个查询 session.sql(SELECT COUNT(*) FROM products).execute(); session.sql(SHOW TABLE STATUS).execute(); EOF4. 高级运维脚本开发4.1 连接监控增强版原始processlist脚本的增强版本#!/bin/bash # 参数化配置 INTERVAL${1:-10} # 默认监控10秒 MAX_CONNECTIONS${2:-100} while true; do TIMESTAMP$(date %Y%m%d%H%M%S) LOG_FILEconnections_${TIMESTAMP}.log # 获取完整processlist mysql -u$MYSQL_USER -p$MYSQL_PASS -e SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, SUBSTRING(INFO, 1, 100) AS QUERY_PREVIEW FROM information_schema.PROCESSLIST ORDER BY TIME DESC; $LOG_FILE # 分析连接数 TOTAL_CONNS$(wc -l $LOG_FILE) ACTIVE_CONNS$(grep -c -v Sleep $LOG_FILE) echo [$(date %Y-%m-%d %H:%M:%S)] 总连接数: $TOTAL_CONNS, 活跃连接: $ACTIVE_CONNS # 预警机制 if [ $TOTAL_CONNS -gt $MAX_CONNECTIONS ]; then echo ⚠️ 警告: 连接数超过阈值($MAX_CONNECTIONS) | tee -a $LOG_FILE # 这里可以添加邮件/短信报警逻辑 fi sleep $INTERVAL done新增功能可配置监控间隔连接数阈值预警查询内容截取展示活跃连接统计持续监控模式4.2 多服务器管理模板批量查询脚本的模板化改进#!/bin/bash # 服务器清单文件格式 # IP,USER,PORT,PASSWORD,DESCRIPTION SERVER_LISTservers.csv OUTPUT_DIRreports mkdir -p $OUTPUT_DIR # 检查依赖 require_cmd() { if ! command -v $1 /dev/null; then echo ❌ 需要安装 $1 exit 1 fi } require_cmd mysql require_cmd csvtool # 主流程 while IFS, read -r ip user port password description; do echo 正在检查服务器: $description ($ip) REPORT_FILE${OUTPUT_DIR}/${ip}_report_$(date %Y%m%d).txt # 检查连通性 if ! nc -z -w 3 $ip $port; then echo ❌ 无法连接 $ip:$port | tee $REPORT_FILE continue fi # 收集关键指标 { echo 服务器: $description ($ip) echo 1. 基础信息 mysql -h $ip -P $port -u $user -p$password -e SELECT version, hostname echo \n2. 关键参数 mysql -h $ip -P $port -u $user -p$password -e SHOW GLOBAL VARIABLES WHERE Variable_name IN (max_connections,innodb_buffer_pool_size,sync_binlog); echo \n3. 运行状态 mysql -h $ip -P $port -u $user -p$password -e SHOW GLOBAL STATUS WHERE Variable_name IN (Threads_connected,Threads_running,Queries); } $REPORT_FILE echo ✅ 报告已生成: $REPORT_FILE done (csvtool namedcol IP,USER,PORT,PASSWORD,DESCRIPTION $SERVER_LIST)5. 性能监控与优化5.1 实时性能监控脚本#!/bin/bash # 监控配置 INTERVAL5 DURATION60 # 检查InnoDB状态函数 check_innodb_status() { mysql -u$MYSQL_USER -p$MYSQL_PASS -e SHOW ENGINE INNODB STATUS\G innodb_status.log # 分析锁等待 grep -A 10 LATEST DETECTED DEADLOCK innodb_status.log grep lock wait innodb_status.log | wc -l } # 主监控循环 end_time$((SECONDS DURATION)) while [ $SECONDS -lt $end_time ]; do # 获取基础指标 metrics$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e SHOW GLOBAL STATUS WHERE Variable_name IN ( Threads_connected, Threads_running, Queries, Slow_queries, Innodb_row_lock_waits ); ) # 处理指标 threads_connected$(echo $metrics | grep Threads_connected | awk {print $2}) queries_per_sec$(echo $metrics | grep Queries | awk {print $2}) # 输出监控信息 echo [$(date %H:%M:%S)] 连接数: $threads_connected, QPS: $queries_per_sec # 异常检测 if [ $threads_connected -gt 100 ]; then check_innodb_status fi sleep $INTERVAL done5.2 自动化索引分析#!/bin/bash # 参数检查 if [ -z $1 ]; then echo 使用方法: $0 数据库名 exit 1 fi DB_NAME$1 # 生成索引分析报告 REPORT_FILEindex_report_${DB_NAME}_$(date %Y%m%d).html # 使用CSS美化报告 cat EOF $REPORT_FILE html head style body { font-family: Arial, sans-serif; margin: 20px; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } tr:nth-child(even) { background-color: #f2f2f2; } .warning { background-color: #fff3cd; } .danger { background-color: #f8d7da; } /style titleMySQL索引分析报告 - $DB_NAME/title /head body h1MySQL索引分析报告 - $DB_NAME/h1 p生成时间: $(date)/p EOF # 查询缺少索引的表 mysql -u$MYSQL_USER -p$MYSQL_PASS $DB_NAME -e SELECT t.TABLE_NAME, t.TABLE_ROWS, COUNT(i.INDEX_NAME) AS INDEX_COUNT, ROUND(t.DATA_LENGTH/1024/1024,2) AS SIZE_MB FROM information_schema.TABLES t LEFT JOIN information_schema.STATISTICS i ON t.TABLE_SCHEMA i.TABLE_SCHEMA AND t.TABLE_NAME i.TABLE_NAME WHERE t.TABLE_SCHEMA $DB_NAME GROUP BY t.TABLE_NAME, t.TABLE_ROWS, t.DATA_LENGTH HAVING INDEX_COUNT 1 ORDER BY t.TABLE_ROWS DESC; $REPORT_FILE echo /body/html $REPORT_FILE echo 索引分析报告已生成: $REPORT_FILE6. 安全与维护最佳实践6.1 自动化备份方案#!/bin/bash # 备份配置 BACKUP_DIR/data/mysql_backups KEEP_DAYS7 TIMESTAMP$(date %Y%m%d_%H%M%S) # 创建备份目录 mkdir -p $BACKUP_DIR # 获取数据库列表 DATABASES$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e SHOW DATABASES; | grep -Ev (Database|information_schema|performance_schema|mysql|sys)) # 备份函数 backup_database() { local db$1 local backup_file${BACKUP_DIR}/${db}_${TIMESTAMP}.sql.gz echo 备份数据库: $db mysqldump -u$MYSQL_USER -p$MYSQL_PASS \ --single-transaction \ --routines \ --triggers \ --events \ $db | gzip $backup_file # 验证备份 if [ ${PIPESTATUS[0]} -ne 0 ]; then echo ❌ 备份失败: $db rm -f $backup_file return 1 fi echo ✅ 备份成功: $(ls -lh $backup_file) return 0 } # 主备份流程 for db in $DATABASES; do backup_database $db done # 清理旧备份 find $BACKUP_DIR -name *.sql.gz -mtime $KEEP_DAYS -delete6.2 用户权限审计脚本#!/bin/bash # 生成用户权限报告 REPORT_FILEmysql_user_audit_$(date %Y%m%d).csv # CSV表头 echo 用户名,主机,全局权限,数据库权限,表权限,列权限 $REPORT_FILE # 查询用户权限 mysql -u$MYSQL_USER -p$MYSQL_PASS -e SELECT CONCAT(\, user, \\, host, \) AS user_host, IFNULL(global_privs, ) AS global_privs, IFNULL(db_privs, ) AS db_privs, IFNULL(table_privs, ) AS table_privs, IFNULL(column_privs, ) AS column_privs FROM ( SELECT u.user, u.host, (SELECT GROUP_CONCAT(privilege_type) FROM information_schema.user_privileges WHERE grantee CONCAT(\, u.user, \\, u.host, \)) AS global_privs, (SELECT GROUP_CONCAT(CONCAT(table_schema, :, privilege_type)) FROM information_schema.schema_privileges WHERE grantee CONCAT(\, u.user, \\, u.host, \) GROUP BY grantee) AS db_privs, (SELECT GROUP_CONCAT(CONCAT(table_schema, ., table_name, :, privilege_type)) FROM information_schema.table_privileges WHERE grantee CONCAT(\, u.user, \\, u.host, \) GROUP BY grantee) AS table_privs, (SELECT GROUP_CONCAT(CONCAT(table_schema, ., table_name, ., column_name, :, privilege_type)) FROM information_schema.column_privileges WHERE grantee CONCAT(\, u.user, \\, u.host, \) GROUP BY grantee) AS column_privs FROM mysql.user u WHERE u.user NOT IN (mysql.sys,mysql.session,mysql.infoschema) ) t ORDER BY user, host; $REPORT_FILE echo 用户权限审计报告已生成: $REPORT_FILE7. 脚本维护与优化建议在实际使用这些脚本的过程中我总结了以下几点经验日志记录标准化所有脚本都应该实现统一的日志格式建议包含时间戳脚本名称执行结果成功/失败关键指标数值错误信息如失败参数化设计好的运维脚本应该做到所有配置参数外部化支持命令行参数覆盖提供--help帮助信息有默认值但可配置错误处理三原则失败立即终止set -e错误信息明确指向问题根源提供修复建议性能考虑批量操作使用事务避免在循环中频繁连接数据库大数据量操作添加进度显示安全加固密码等敏感信息加密存储配置文件设置严格权限操作前进行二次确认一个典型的改进示例#!/bin/bash # 增强版脚本模板 set -euo pipefail # 配置加载 CONFIG_FILE${SCRIPT_DIR}/config.cfg [ -f $CONFIG_FILE ] source $CONFIG_FILE # 日志函数 log() { local level$1 local message$2 echo [$(date %Y-%m-%d %H:%M:%S)] [$level] $message | tee -a $LOG_FILE } # 主流程 main() { log INFO 脚本启动 # 业务逻辑 if [ ! -d $BACKUP_DIR ]; then log ERROR 备份目录不存在: $BACKUP_DIR exit 1 fi # ... log INFO 脚本执行完成 } # 异常处理 trap log ERROR 脚本异常退出; exit 1 ERR trap log INFO 脚本被用户中断; exit 2 INT TERM main $通过持续优化脚本的健壮性和可维护性可以确保这些自动化工具长期稳定地为运维工作服务。
返回列表