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

mysql,binlog · 浏览次数 : 0

小编点评

**文件:check_bintime.py** ```python import binascii import re # 设置文件路径 file_path = "/data/mysql/bin_logs/mysql_binlog.000055" # 读取文件头 with open(file_path, "rb") as f: binlog_head = f.read(4) # 解析头部信息 match = re.match(r"\x[0-9a-f]{4}", binlog_head) if match: start_time = match.group() # 获取结束时间 binlog_end_time = re.search(r"\x[0-9a-f]{4}", binlog_head[4:]) if binlog_end_time: end_time = binlog_end_time.group() # 计算轮转时间 elapsed_time = end_time - start_time # 打印结果 print("开始时间:", start_time) print("结束时间:", end_time) print("轮转时间:", elapsed_time) ``` **使用方法:** 1. 将 `file_path` 替换为您的实际文件路径。 2. 保存脚本为 `find_binlog_start_end_time.py`。 3. 运行脚本:`python find_binlog_start_end_time.py`。 **注意:** * 该脚本使用正则表达式来解析文件头,该方法可能不适用于所有文件格式。 * 脚本假设文件以 `ASCII` 格式存在。 * 脚本只显示轮转时间,如果需要获取结束时间,请手动提取。

正文

之前写过一篇文章MySQL如何获取binlog的开始时间和结束时间[1],文章里面介绍了如何获取MySQL数据库二进制日志(binlog)的开始时间与结束时间的一些方法。实际应用当中,我们可能还会遇到效率/性能方面的问题。最近对这个问题做了一些研究,这里就介绍一下如何快速获取MySQL二进制日志(binlog)的开始时间和结束时间。

我们下来看看当MySQL二进制日志(binlog)的Size很大的时候,获取起开始时间和结束时间,如下测试所示

$ du -sh mysql_binlog.000105
1.1G    mysql_binlog.000105
$ time mysqlbinlog  mysql_binlog.000105 |grep "Start: binlog" | awk -F "server id" '{print $1}'
#240425  9:20:26 

real    0m34.136s
user    0m25.941s
sys     0m11.985s

从上面实验可以看出,在MySQL二进制日志(binlog)变大的情况下,这种方法需要34秒,非常低效和耗时,那么我们怎么提升性能呢? 我们改写一下脚本,如下所示

$ time mysqlbinlog  mysql_binlog.000105 | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'
#240425  9:20:26 

real    0m0.010s
user    0m0.006s
sys     0m0.005s

如上所示,这样改进脚本后,性能效率已经提升到0.01秒,已经相当的高效了。那么获取结束时间能否也可以这样提升呢? 很遗憾的是由于MySQL二进制日志(binlog)的结束时间/滚动时间(Rotate Time)位于文件的末尾,由于管道的一些基本特性,获取MySQL二进制日志(binlog)的结束时间无法通过上面方法来优化,这里不打算介绍Linux管道相关概念,所以我们只需知道这么一个事实。

如果你对Linux管道的一些原理不是很清楚,那么就用实验测试验证一下,如下所示:

$ time mysqlbinlog  mysql_binlog.000105  |grep Rotate | awk -F "server id" '{print $1}'
#240426 11:11:37 

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

real    0m33.917s
user    0m25.528s
sys     0m11.395s

那么怎么来优化获取MySQL二进制日志(binlog)的结束时间呢?经过一番观察与实验,我发现一个MySQL二进制日志(binlog)的结束时间,就是下一个二进制日志(binlog)的开始时间。如下实验所示

[mysql@dbtest04 bin_logs]$ ls -lrt
total 28
-rw-r----- 1 mysql mysql 207 May  9 15:25 mysql_binlog.000055
-rw-r----- 1 mysql mysql 207 May  9 15:27 mysql_binlog.000056
-rw-r----- 1 mysql mysql 207 May 10 11:02 mysql_binlog.000057
-rw-r----- 1 mysql mysql 207 May 10 11:34 mysql_binlog.000058
-rw-r----- 1 mysql mysql 207 May 10 11:38 mysql_binlog.000059
-rw-r----- 1 mysql mysql 157 May 10 11:38 mysql_binlog.000060
-rw-r----- 1 mysql mysql 246 May 10 11:38 mysql_binlog.index
[mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000055 | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'
#240509 14:48:10 
[mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000055  |grep Rotate | awk -F "server id" '{print $1}'
#240509 15:25:57 
[mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000056 | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'
#240509 15:25:57 
[mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000056  |grep Rotate | awk -F "server id" '{print $1}'
#240509 15:27:37 
[mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000057 | head -10 | grep "Start: binlog" | awk -F "server id" '{print $1}'
#240509 15:27:37 
[mysql@dbtest04 bin_logs]$ mysqlbinlog  mysql_binlog.000057  |grep Rotate | awk -F "server id" '{print $1}'
#240510 11:02:00 
[mysql@dbtest04 bin_logs]$

如果全部符合这个规律的话,那么我们直接用下一个binlog的开始时间作为上一个binlog的结束时间即可,于是我写了一个脚本find_binlog_start_end_time.sh:

#!/bin/bash

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

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


if [ $# = 0 ]
then
   echo "find_binlog_start_end_time.sh Usage:"
   echo "for eg: find_binlog_start_end_time.sh  /data/mysql/binlogs"
   exit
fi

BINLOG_FILE_PATH=$1

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

index=1
start_time=""
end_time=""
last_binlog_name=""



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

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

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

         echo "file name:$last_binlog_name" , "start time:$start_time""end time:$end_time"
         if [ $index -eq $BINLOG_FILE_NUM ];then
            last_end_time=`$MYSQLBINLOG  $binlog_file |tail -10 | egrep "Rotate|Stop" | awk -F "server id" '{print $1}'`
            echo "file name:$binlog_file" , "start time:$end_time""end time:$last_end_time"
         else  
            start_time=$end_time
            last_binlog_name=$binlog_file
         fi
       fi
      
      let index++
  done

如下测试所示

[mysql@dbtest04 kerry]$ sh  find_binlog_start_end_time.sh /data/mysql/bin_logs/
file name:mysql_binlog.000055 , start time:#240509 14:48:10 , end time:#240509 15:25:57 
file name:mysql_binlog.000056 , start time:#240509 15:25:57 , end time:#240509 15:27:37 
file name:mysql_binlog.000057 , start time:#240509 15:27:37 , end time:#240510 11:02:00 
file name:mysql_binlog.000058 , start time:#240510 11:02:00 , end time:#240510 11:34:01 
file name:mysql_binlog.000059 , start time:#240510 11:34:01 , end time:#240510 11:38:24 
file name:mysql_binlog.000060 , start time:#240510 11:38:24 , end time:#240510 16:45:34 
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]我们来看看实验结果,如下所示

$ python3 check_bintime.py  /data/mysql/bin_logs/mysql_binlog.index
{'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'}
{'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'}
{'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'}
{'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'}
{'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'}
{'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'}
{'file_name''mysql_binlog.000061''binlog_size''157.0 B''start_time''2024-05-10 16:45:34''end_time''now'}

shell脚本来自一种快速取得binlog开始时间的方法[3]:

[mysql@dbtest04 kerry]$ function getBinlogStartTime()
> {
>         theFile="$1"
>         #取出文件头做分析
>         binlogHead=`hexdump ${theFile} | head -1`
>         #binlog文件校验
>         binlogCrc=`echo $binlogHead | awk '{print $1$2$3}'`
>         if [ "${binlogCrc}" != '000000062fe6e69' ]; then
>                 echo '${theFile} is damage.'
>                 exit 1
>         fi
>         #计算binlog的开始时间
>         binlogBeginTimeInt=`echo $binlogHead | awk '{print $5$4}' | gawk ' { printf strtonum("0x" $0)}' `
>         binlogBeginTime=`date -d "1970-01-01 UTC $binlogBeginTimeInt seconds" "+%F %T"`
>         echo $binlogBeginTime
> }
[mysql@dbtest04 kerry]$ getBinlogStartTime /data/mysql/bin_logs/mysql_binlog.000055
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

与MySQL如何快速获取binlog的开始时间和结束时间相似的内容:

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

之前写过一篇文章MySQL如何获取binlog的开始时间和结束时间[1],文章里面介绍了如何获取MySQL数据库二进制日志(binlog)的开始时间与结束时间的一些方法。实际应用当中,我们可能还会遇到效率/性能方面的问题。最近对这个问题做了一些研究,这里就介绍一下如何快速获取MySQL二进制日志(b

【转帖】MySQL索引

数据表如何用索引快速查找 索引是 排好序的快速查找的数据结构 索引存储在文件系统中 索引的文件存储形式与存储引擎有关 索引数据结构:可以是二叉树、红黑树、Hash表、B-Tree、B+Tree 1、二叉树 使用索引的如下图:(如果是使用二叉树结构)每一个节点都存放数据行的磁盘地址【快速定位到数据】

MySQL索引

索引的概述 索引是一种用于快速查询和检索数据的数据结构,其本质可以看成是一种排序好的数据结构。索引的作用就相当于书的目录。打个比方: 我们在查字典的时候,如果没有目录,那我们就只能一页一页的去找我们需要查的那个字,速度很慢。如果有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。索

MySQL如何查询某个字段含有字母数字的值

在MySQL中,要查询某个字段含有字母和数字的值,可以使用正则表达式配合REGEXP操作符。以下是一个详细的示例,说明如何编写这样的查询。 假设我们有一个名为my_table的表,其中有一个名为my_column的字段,我们想要查询这个字段中含有字母和数字的值。 1.使用正则表达式 正则表达式[a-

mysql 大表如何ddl 👑

大家好,我是蓝胖子,mysql对大表(千万级数据)的ddl语句,在生产上执行时一定要千万小心,一不小心就有可能造成业务阻塞,数据库io和cpu飙高的情况。今天我们就来看看如何针对大表执行ddl语句。 通过这篇文章,你能了解到下面的知识点, ![Pasted image 20230831165346.

MySQL 分表查询

分表是一种数据库分割技术,用于将大表拆分成多个小表,以提高数据库的性能和可管理性。在MySQL中,可以使用多种方法进行分表,例如基于范围、哈希或列表等。下面将详细介绍MySQL如何分表以及分表后如何进行数据查询。 基于哈希的分表 基于哈希的分表是一种将数据分散到多个子表中的数据库分表策略。这种方法通

聊聊MySQL是如何处理排序的

在MySQL的查询中常常会用到 order by 和 group by 这两个关键字,它们的相同点是都会对字段进行排序,那查询语句中的排序是如何实现的呢?

面试必问:MySQL死锁 是什么,如何解决?(史上最全)

MySQL死锁接触少,但面试又经常被问到怎么办? 最近有小伙伴在面试的时候,被问了MySQL死锁,如何解决? 虽然也回答出来了,但是不够全面体系化, 所以,小北给大家做一下系统化、体系化的梳理,帮助大家在面试过程中能够脱颖而出,拿到自己心仪的Offer 插播一条:如果你近期准备面试跳槽,建议在htt

[转帖]Oracle、MySQL、PG是如何处理数据库“半页写”的问题的?

数据库“断页”是个很有意思的话题,目前任何数据库应该都绕不过去。我们知道数据库的块大小一般是8k、16k、32k,而操作系统块大小是4k,那么在数据库刷内存中的数据页到磁盘上的时候,就有可能中途遭遇类似操作系统异常断电而导致数据页部分写的情况,进而造成数据块损坏,数据块损坏对于某些数据库是致命的,可

一条SQL如何被MySQL架构中的各个组件操作执行的?

摘要:一条SQL如何被MySQL架构中的各个组件操作执行的,执行器做了什么?存储引擎做了什么?表关联查询是怎么在存储引擎和执行器被分步执行的?本文带你探探究竟! 本文分享自华为云社区《一条SQL如何被MySQL架构中的各个组件操作执行的?》,作者:砖业洋__。 1. 单表查询SQL在MySQL架构中