尝试用shell脚本实现mysql日志分析工具

发布于 2024-11-26  160 次阅读


一、前因

我们公司服务器偶尔会因为各种误操作,导致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

那如果我要查看平均时间最长的命令是在什么时候执行的呢,因为可能不是人手动执行的


公交车司机终于在众人的指责中将座位让给了老太太