一、前因
我们公司服务器偶尔会因为各种误操作,导致CPU占满,基本就是mysql的问题,但是我们急于恢复,一般都是直接重启就完事。无法及时的查明到底是为什么导致的mysql占满CPU。网上也不是没有mysql监控软件,但是大多都是监控死锁、线程、磁盘IO、网络之类的服务器参数,无法第一时间找到是哪个语句导致崩溃。网上现成的免费不好用,好用的收费。就想着自己用命令行整一个简易的。满足我们分析日志需求就行
二、整理需求
要做功能必定要先整理清楚需求,我的需求大致如下
- 实时查看当前的查询日志,这一点可以通过navicat以及mysql自带的命令行完成。看能不能集成到我shell脚本中,并定期刷新
- 查看往天储存的慢查询日志,来找到平均耗时最多的SQL语句,通过语句来排除故障,这样即使是几天后都能排查当天的故障原因
- 查看当天的慢查询日志,如果第一时间是重启,那么重启之后第一时间就是查看当天的慢查询日志。通过当天的日志快速判断问题
- 精准定位问题,通过观察日志的SQL执行频率,以及具体的执行时间,来进一步判断是谁在什么时间或者多高的频率操作的SQL语句导致的卡死
三、万事开头难,说干就干
1.实现将navicat的服务器监控,也就是SHOW FULL PROCESSLIST展现出来,其实这一点navicat看着更直观,只是想着用一个脚本实现,免得两头跑
#!/bin/bash
#定义数据库连接信息
DB_HOST="localhost"
DB_USER="root"
DB_PASS="xxxxxxxxxxx"
##定义今天mysql慢查询日志路径
DB_TODAY_SLOW="/www/server/data/mysql-slow.log"
##定义往天mysql慢查询日志路径
DB_LOG_SLOW="/www/server/data/mysql-every-slow/"
# 定义一个函数来查看实时进程状态
function show_processlist {
while true; do
# 清屏
clear
# 执行 SHOW FULL PROCESSLIST
mysql -u$DB_USER -p$DB_PASS -e "SHOW FULL PROCESSLIST;" | column -t | cut -c1-100
# 提示用户按 q 退出或 Enter 返回
echo ""
echo "这里仅提供简单的实时查看,要查看完整语句还是推荐用navicat的服务器监控,更直观也更完整,这里要留意Execute以及Query状态情况下且时间特别长的语句,说明这个语句查询了特别久的时间"
echo " "
echo "按 q 退出实时查看,按 z 返回主菜单..."
# 通过 `read` 监听用户输入,但使用 `-t 1` 使其只等待 1 秒钟
read -t 1 -n 1 -s input
# 如果用户输入了 q,则退出实时查看
if [[ "$input" == "q" ]]; then
break
fi
# 如果用户按了 z 键,返回到菜单
if [[ "$input" == "z" ]]; then
show_menu # 使用 return 跳出当前函数,返回到菜单
fi
# 每次刷新 1 秒
sleep 1
done
}
function show_today {
/www/server/mysql/bin/mysqldumpslow -s at $DB_TODAY_SLOW
}
function show_menu {
# 设置每行显示一个选项
LINES=4
PS3="请输入数字选择一个选项: "
select option in "查看语句实时查看状态" "查看当天语句查询记录" "查看往天语句查询记录" "一键三连?"
do
echo
case $option in
"查看语句实时查看状态")
echo "1.查看语句实时查看状态"
show_processlist
break
;;
"查看当天语句查询记录")
echo "查看当天语句查询记录"
show_today
break
;;
"查看往天语句查询记录")
echo "查看往天语句查询记录"
break
;;
"一键三连?")
echo "一键三连功能"
break
;;
*)
echo "无效选项,请重新选择"
;;
esac
done
}
# 主程序入口
show_menu
从这一步来说,claude在代码层面其实是比ChatGPT聪明点的。chatgpt也是这么展现的,但是超出的info执行语句会跨行导致排版混乱。然后chatgpt给出的方法就是用awk进行截断。但是总是截断不好,而claude给出的方案就是
mysql -u$DB_USER -p$DB_PASS -e "SHOW FULL PROCESSLIST;" | column -t | cut -c1-100
具体实现出来的效果就是下面的图

2.查看当天的慢查询语句,按照平均执行时间排序,按照平均时间执行这一步chatgpt也没给出一个好方案,这一点上甚至不如百度,我用claude执行了如下命令来实现
function show_today {
/www/server/mysql/bin/mysqldumpslow -s at $DB_TODAY_SLOW
}
因为我们服务器做了日志切割,将慢查询日志按天储存,按月分文件夹,这样看起来就方便些,具体脚本如下
#!/bin/bash
# MySQL慢查询日志文件路径
slow_query_log_file="/www/server/data/mysql-slow.log"
# 保存日志文件的目录路径
log_directory="/www/server/data/mysql-slow-everyday"
# 获取前一天日期
current_date=$(date -d yesterday +"%Y-%m-%d")
# 切割慢查询日志文件为每天一份,并以日期命名
#mv "$slow_query_log_file" "$log_directory/slow_$current_date.log"
# 按年-月文件夹分类保存
year=$(date -d yesterday +"%Y")
month=$(date -d yesterday +"%m")
year_month_directory="$log_directory/$year-$month"
mkdir -p "$year_month_directory"
mv "$slow_query_log_file" "$year_month_directory/slow_$current_date.log"
# 用数据库管理员权限重新更新下日志文件,否则新日志会存到移动后的日志文件里面
/www/server/mysql/bin/mysqladmin -uroot -p0xxxxx flush-logs
那如果我要查看平均时间最长的命令是在什么时候执行的呢,因为可能不是人手动执行的
叨叨几句... NOTHING