运维脚本示例:MySQL 备份、主从监控与 Nginx 日志
请在实际环境中替换密码、路径与收件人。
一、MySQL:按库整库备份(单循环)
对每个非系统库生成一个带时间戳的 .sql 文件。
shell
#!/bin/bash
DATE=$(date +%F_%H-%M-%S)
HOST=localhost
USER=backup
PASS='请填写备份账号密码或使用环境变量 MYSQL_BACKUP_PASS'
BACKUP_DIR=/data/db_backup
DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys")
for DB in $DB_LIST; do
BACKUP_NAME=$BACKUP_DIR/${DB}_${DATE}.sql
if ! mysqldump -h$HOST -u$USER -p$PASS -B $DB > $BACKUP_NAME 2>/dev/null; then
echo "$BACKUP_NAME 备份失败!"
fi
done补充:-p 紧跟密码会在 ps 中暴露;生产环境常用 ~/.my.cnf 权限 600 或专用备份账号 + 最小权限。
二、MySQL:库 → 表逐级备份(嵌套循环)
每个库一个目录,每张表单独 SQL 文件,适合极大库或需要按表恢复的场景。
shell
#!/bin/bash
DATE=$(date +%F_%H-%M-%S)
HOST=localhost
USER=backup
PASS='请填写备份账号密码或使用环境变量 MYSQL_BACKUP_PASS'
BACKUP_DIR=/data/db_backup
DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys")
for DB in $DB_LIST; do
BACKUP_DB_DIR=$BACKUP_DIR/${DB}_${DATE}
[ ! -d $BACKUP_DB_DIR ] && mkdir -p $BACKUP_DB_DIR &>/dev/null
TABLE_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "use $DB;show tables;" 2>/dev/null)
for TABLE in $TABLE_LIST; do
BACKUP_NAME=$BACKUP_DB_DIR/${TABLE}.sql
if ! mysqldump -h$HOST -u$USER -p$PASS $DB $TABLE > $BACKUP_NAME 2>/dev/null; then
echo "$BACKUP_NAME 备份失败!"
fi
done
done三、MySQL 主从:Slave_IO_Running / Slave_SQL_Running
从 show slave status 解析运行状态,不为 Yes 则发邮件(需已配置 mail)。
shell
#!/bin/bash
HOST=localhost
USER=root
PASSWD='请填写监控用只读账号密码'
IO_SQL_STATUS=$(mysql -h$HOST -u$USER -p$PASSWD -e 'show slave status\G' 2>/dev/null |awk '/Slave_.*_Running:/{print $1$2}')
for i in $IO_SQL_STATUS; do
THREAD_STATUS_NAME=${i%:*}
THREAD_STATUS=${i#*:}
if [ "$THREAD_STATUS" != "Yes" ]; then
echo "Error: MySQL Master-Slave $THREAD_STATUS_NAME status is $THREAD_STATUS!" | mail -s "Master-Slave Status" alert@example.com
fi
done补充:MySQL 8.0.22+ 复制线程字段曾更名(Replica_*),新版本请对照官方文档调整 awk 模式。
四、Nginx:按日归档访问日志
将指定日志移到按年月创建的目录,文件名带昨日日期,并向 master 发 USR1 促使重新打开日志文件。
shell
#!/bin/bash
LOG_DIR=/usr/local/nginx/logs
YESTERDAY_TIME=$(date -d "yesterday" +%F)
LOG_MONTH_DIR=$LOG_DIR/$(date +"%Y-%m")
LOG_FILE_LIST="default.access.log"
for LOG_FILE in $LOG_FILE_LIST; do
[ ! -d $LOG_MONTH_DIR ] && mkdir -p $LOG_MONTH_DIR
mv $LOG_DIR/$LOG_FILE $LOG_MONTH_DIR/${LOG_FILE}_${YESTERDAY_TIME}
done
kill -USR1 $(cat /var/run/nginx.pid)补充:date -d 为 GNU date;macOS/BSD 需改用 -v-1d 等写法。nginx.pid 路径以实际配置为准。
五、Nginx 访问日志简单分析
假定日志格式包含:$remote_addr、时间、$request、$status 等(见脚本内注释)。
shell
#!/bin/bash
# 日志格式: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"
LOG_FILE=$1
echo "统计访问最多的10个IP"
awk '{a[$1]++}END{print "UV:",length(a);for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr |head -10
echo "----------------------"
echo "统计时间段访问最多的IP"
awk '$4>="[01/Dec/2018:13:20:25" && $4<="[27/Nov/2018:16:20:49"{a[$1]++}END{for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr|head -10
echo "----------------------"
echo "统计访问最多的10个页面"
awk '{a[$7]++}END{print "PV:",length(a);for(v in a){if(a[v]>10)print v,a[v]}}' $LOG_FILE |sort -k2 -nr
echo "----------------------"
echo "统计访问页面状态码数量"
awk '{a[$7" "$9]++}END{for(v in a){if(a[v]>5)print v,a[v]}}' $LOG_FILE |sort -k3 -nr补充:时间过滤段里的日期是 示例,请改成你日志里真实存在的时间段;$4 是否为时间字段取决于实际 log_format 字段顺序。
六、小结
- 备份脚本建议再加:磁盘空间检查、备份压缩、保留天数清理、失败告警。
- 日志分析流量大时可换 ClickHouse / ELK;Shell + awk 适合中小规模快速统计。
