翼度科技»论坛 编程开发 mysql 查看内容

MySQL如何快速获取binlog的开始时间和结束时间

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
之前写过一篇文章MySQL如何获取binlog的开始时间和结束时间[1],文章里面介绍了如何获取MySQL数据库二进制日志(binlog)的开始时间与结束时间的一些方法。实际应用当中,我们可能还会遇到效率/性能方面的问题。最近对这个问题做了一些研究,这里就介绍一下如何快速获取MySQL二进制日志(binlog)的开始时间和结束时间。
我们下来看看当MySQL二进制日志(binlog)的Size很大的时候,获取起开始时间和结束时间,如下测试所示
  1. $ du -sh mysql_binlog.000105
  2. 1.1G    mysql_binlog.000105
  3. $ time mysqlbinlog  mysql_binlog.000105 |grep "Start: binlog" | awk -F "server id" '{print $1}'
  4. #240425  9:20:26 

  5. real    0m34.136s
  6. user    0m25.941s
  7. sys     0m11.985s
复制代码
从上面实验可以看出,在MySQL二进制日志(binlog)变大的情况下,这种方法需要34秒,非常低效和耗时,那么我们怎么提升性能呢? 我们改写一下脚本,如下所示
  1. $ time mysqlbinlog  mysql_binlog.000105 | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'
  2. #240425  9:20:26 

  3. real    0m0.010s
  4. user    0m0.006s
  5. sys     0m0.005s
复制代码
如上所示,这样改进脚本后,性能效率已经提升到0.01秒,已经相当的高效了。那么获取结束时间能否也可以这样提升呢? 很遗憾的是由于MySQL二进制日志(binlog)的结束时间/滚动时间(Rotate Time)位于文件的末尾,由于管道的一些基本特性,获取MySQL二进制日志(binlog)的结束时间无法通过上面方法来优化,这里不打算介绍Linux管道相关概念,所以我们只需知道这么一个事实。
如果你对Linux管道的一些原理不是很清楚,那么就用实验测试验证一下,如下所示:
  1. $ time mysqlbinlog  mysql_binlog.000105  |grep Rotate | awk -F "server id" '{print $1}'
  2. #240426 11:11:37 

  3. real    0m34.223s
  4. user    0m27.202s
  5. sys     0m11.551s
  6. $ time mysqlbinlog  mysql_binlog.000105  | tail -10 | grep Rotate | awk -F "server id" '{print $1}'
  7. #240426 11:11:37 

  8. real    0m33.917s
  9. user    0m25.528s
  10. sys     0m11.395s
复制代码
那么怎么来优化获取MySQL二进制日志(binlog)的结束时间呢?经过一番观察与实验,我发现一个MySQL二进制日志(binlog)的结束时间,就是下一个二进制日志(binlog)的开始时间。如下实验所示
  1. [mysql@dbtest04 bin_logs]$ ls -lrt
  2. total 28
  3. -rw-r----- 1 mysql mysql 207 May  9 15:25 mysql_binlog.000055
  4. -rw-r----- 1 mysql mysql 207 May  9 15:27 mysql_binlog.000056
  5. -rw-r----- 1 mysql mysql 207 May 10 11:02 mysql_binlog.000057
  6. -rw-r----- 1 mysql mysql 207 May 10 11:34 mysql_binlog.000058
  7. -rw-r----- 1 mysql mysql 207 May 10 11:38 mysql_binlog.000059
  8. -rw-r----- 1 mysql mysql 157 May 10 11:38 mysql_binlog.000060
  9. -rw-r----- 1 mysql mysql 246 May 10 11:38 mysql_binlog.index
  10. [mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000055 | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'
  11. #240509 14:48:10 
  12. [mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000055  |grep Rotate | awk -F "server id" '{print $1}'
  13. #240509 15:25:57 
  14. [mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000056 | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'
  15. #240509 15:25:57 
  16. [mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000056  |grep Rotate | awk -F "server id" '{print $1}'
  17. #240509 15:27:37 
  18. [mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000057 | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'
  19. #240509 15:27:37 
  20. [mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000057  |grep Rotate | awk -F "server id" '{print $1}'
  21. #240510 11:02:00 
  22. [mysql@dbtest04 bin_logs]$
复制代码
如果全部符合这个规律的话,那么我们直接用下一个binlog的开始时间作为上一个binlog的结束时间即可,于是我写了一个脚本find_binlog_start_end_time.sh:
  1. #!/bin/bash

  2. #########################################################################################
  3. #                                                                                       #
  4. # This script is used for get the binlog start time and end time                        #
  5. #                                                                                       #
  6. #########################################################################################
  7. #                                                                                       #
  8. # ScriptName            :    find_binlog_start_end_time.sh                              #
  9. # Author                :    Kerry                                                      #
  10. # CreateDate            :    2024-05-10                                                 #
  11. # Email                 :    kerry2008code@qq.com                                       #
  12. #***************************************************************************************#
  13. # 参数配置                                                                              #
  14. #---------------------------------------------------------------------------------------#
  15. # 脚本参数   binlog文件存放的路径                                                       #
  16. #---------------------------------------------------------------------------------------#
  17. # MYSQLBINLOG        mysqlbinlog的位置,以防没有设置环境变量                            #
  18. # BINLOG_BASENAME    binlog的前缀名                                                     #
  19. #---------------------------------------------------------------------------------------#
  20. # 注意事项:                                                                            #
  21. #   1:如果维护的MySQL数据库都规范化安装、配置的化,下面很多参数都不需要修改            #
  22. #***************************************************************************************#
  23. # Version        Modified Date            Description                                   #
  24. #***************************************************************************************#
  25. # V.1.0          2024-05-10            创建此脚本                                       #
  26. #########################################################################################

  27. # mysqlbinlog的路径,一般无需设置,以防没有设置环境变量时
  28. MYSQLBINLOG="/opt/mysql/mysql8.0/bin/mysqlbinlog"
  29. BINLOG_BASENAME="mysql_binlog"


  30. if [ $# = 0 ]
  31. then
  32.    echo "find_binlog_start_end_time.sh Usage:"
  33.    echo "for eg: find_binlog_start_end_time.sh  /data/mysql/binlogs"
  34.    exit
  35. fi

  36. BINLOG_FILE_PATH=$1

  37. if [ ! -d $BINLOG_FILE_PATH ];then
  38.     echo "the folder $BINLOG_FILE_PATH does not exist, please check it!"
  39.     exit 1
  40. fi

  41. index=1
  42. start_time=""
  43. end_time=""
  44. last_binlog_name=""



  45. BINLOG_FILE_NUM=`ls -lrt $BINLOG_FILE_PATH |  grep $BINLOG_BASENAME |grep -v $BINLOG_BASENAME.index | wc -l`

  46. if [ $BINLOG_FILE_NUM -lt 1 ];then
  47.     echo "pelase check the binlog or the parameter of this script"
  48.     exit 1;
  49. fi

  50. cd $BINLOG_FILE_PATH
  51. for binlog_file in `ls -rt |  grep $BINLOG_BASENAME |grep -v $BINLOG_BASENAME.index`;
  52.   do
  53.       if [ $index -eq 1 ];then
  54.          start_time=`$MYSQLBINLOG  $binlog_file | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'`
  55.          last_binlog_name=$binlog_file
  56.       else
  57.          end_time=`$MYSQLBINLOG  $binlog_file | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'`

  58.          echo "file name:$last_binlog_name" , "start time:$start_time", "end time:$end_time"
  59.          if [ $index -eq $BINLOG_FILE_NUM ];then
  60.             last_end_time=`$MYSQLBINLOG  $binlog_file |tail -10 | egrep "Rotate|Stop" | awk -F "server id" '{print $1}'`
  61.             echo "file name:$binlog_file" , "start time:$end_time", "end time:$last_end_time"
  62.          else  
  63.             start_time=$end_time
  64.             last_binlog_name=$binlog_file
  65.          fi
  66.        fi
  67.       
  68.       let index++
  69.   done
复制代码
如下测试所示
  1. [mysql@dbtest04 kerry]$ sh  find_binlog_start_end_time.sh /data/mysql/bin_logs/
  2. file name:mysql_binlog.000055 , start time:#240509 14:48:10 , end time:#240509 15:25:57 
  3. file name:mysql_binlog.000056 , start time:#240509 15:25:57 , end time:#240509 15:27:37 
  4. file name:mysql_binlog.000057 , start time:#240509 15:27:37 , end time:#240510 11:02:00 
  5. file name:mysql_binlog.000058 , start time:#240510 11:02:00 , end time:#240510 11:34:01 
  6. file name:mysql_binlog.000059 , start time:#240510 11:34:01 , end time:#240510 11:38:24 
  7. file name:mysql_binlog.000060 , start time:#240510 11:38:24 , end time:#240510 16:45:34 
  8. file name:mysql_binlog.000061 , start time:#240510 16:45:34 , end time:
复制代码
另外,还有一种比较高效的方法是解析二进制日志的头部信息(此篇文章统统指binlog v 4),因为binlog的头部由固定的4个字节组成,而头部信息的FORMAT_DESCRIPTION_EVENT部分包含了binlog的开始时间,我在搜索/学习相关资料时,结果发现有人已经总结过这方面的内容,而且已经有相关Python脚本或shell脚本了,这里就重复造轮子了,Python脚本来自MySQL 查询binlog生成时间[2]我们来看看实验结果,如下所示
  1. $ python3 check_bintime.py  /data/mysql/bin_logs/mysql_binlog.index
  2. {'file_name': 'mysql_binlog.000055', 'binlog_size': '207.0 B', 'start_time': '2024-05-09 14:48:10', 'end_time': '2024-05-09 15:25:57'}
  3. {'file_name': 'mysql_binlog.000056', 'binlog_size': '207.0 B', 'start_time': '2024-05-09 15:25:57', 'end_time': '2024-05-09 15:27:37'}
  4. {'file_name': 'mysql_binlog.000057', 'binlog_size': '207.0 B', 'start_time': '2024-05-09 15:27:37', 'end_time': '2024-05-10 11:02:00'}
  5. {'file_name': 'mysql_binlog.000058', 'binlog_size': '207.0 B', 'start_time': '2024-05-10 11:02:00', 'end_time': '2024-05-10 11:34:01'}
  6. {'file_name': 'mysql_binlog.000059', 'binlog_size': '207.0 B', 'start_time': '2024-05-10 11:34:01', 'end_time': '2024-05-10 11:38:24'}
  7. {'file_name': 'mysql_binlog.000060', 'binlog_size': '180.0 B', 'start_time': '2024-05-10 11:38:24', 'end_time': '2024-05-10 16:45:34'}
  8. {'file_name': 'mysql_binlog.000061', 'binlog_size': '157.0 B', 'start_time': '2024-05-10 16:45:34', 'end_time': 'now'}
复制代码
shell脚本来自一种快速取得binlog开始时间的方法[3]:
  1. [mysql@dbtest04 kerry]$ function getBinlogStartTime()
  2. > {
  3. >         theFile="$1"
  4. >         #取出文件头做分析
  5. >         binlogHead=`hexdump ${theFile} | head -1`
  6. >         #binlog文件校验
  7. >         binlogCrc=`echo $binlogHead | awk '{print $1$2$3}'`
  8. >         if [ "${binlogCrc}" != '000000062fe6e69' ]; then
  9. >                 echo '${theFile} is damage.'
  10. >                 exit 1
  11. >         fi
  12. >         #计算binlog的开始时间
  13. >         binlogBeginTimeInt=`echo $binlogHead | awk '{print $5$4}' | gawk ' { printf strtonum("0x" $0)}' `
  14. >         binlogBeginTime=`date -d "1970-01-01 UTC $binlogBeginTimeInt seconds" "+%F %T"`
  15. >         echo $binlogBeginTime
  16. > }
  17. [mysql@dbtest04 kerry]$ getBinlogStartTime /data/mysql/bin_logs/mysql_binlog.000055
  18. 2024-05-09 14:48:10
复制代码
不过你看其脚本也会发现,解析MySQL的binlog的头部文件,比较容易获取binlog的开始时间,而获取binlog的结束时间/轮转时间就比较麻烦了。所以python脚本中获取binlog结束时间的思路跟我的思路也是一样的。
总结:

这里介绍了两种快速获取binlog的开始时间和结束时间的两种方法,这两种方法都非常高效,至于我写的脚本find_binlog_start_end_time.sh目前还比较粗糙,后面有时间再完善补充。
参考资料

[1] 1: https://www.cnblogs.com/kerrycode/p/17377899.html
[2] 2: https://blog.csdn.net/qq_42768234/article/details/126970988
[3] 3: https://blog.csdn.net/shaochenshuo/article/details/120549377
扫描上面二维码关注我如果你真心觉得文章写得不错,而且对你有所帮助,那就不妨帮忙“推荐"一下,您的“推荐”和”打赏“将是我最大的写作动力!本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.
来源:https://www.cnblogs.com/kerrycode/p/18186152
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具