mysqlbinlog转换_binlog⽂件分析与mysqlbinlog⼯具的修改
(转)
问题
本⽂主要带着以下问题进⾏学习:
1、什么是binlog,有什么作⽤
2、binlog有哪些格式
3、分析⼀条典型binlog ,说明从binlog中可以得到哪些信息
4、如何修改mysqlbinlog,使得可以显⽰最后⼀条记录
这⾥主要考虑binlog的使⽤及相关格式,⽽不是关注binlog的写⼊时机。
⼀、简介
binlog⼜叫⼆进制⽇志⽂件,它会将mysql中所有修改数据库数据的Query以⼆进制的形式记录到⽇志⽂件中,如:
create,insert,drop,update等;(对于select操作则不会被记录到binlog⾥,因为它并没有修改数据库的数据)。binlog⼀般存储在数据⽬录下,并且命名为:mysql-bin.***(这个可以在配置⽂件中修改myf:log-bin=mysql-bin,就是⽂件名的前缀;mysqld在每个
binlog
名后⾯添加⼀个数字扩展名。每次启动服务器或刷新⽇志时增加⽂件的⼤⼩⼤于max_binlog_size,⼀个事务不会被拆分开)。
binlog主要是⽤于保证数据完整的,如主从备份,通过从binlog⽂件中读取操作来在salve机上进⾏同样的操作,保证主从备份,当然不可能每次都从开始的地⽅redo,所以每条记录都有⼀个时间截TIMESTAMP。
⼆、简单的使⽤binlog
show binary logs;
#显⽰binlog⽂件
purge binary logsto 'mysql-bin.**' #删除到**⽂件
bin/mysqlbinlog binlogfile #解析binlog⽂件
利⽤binlog恢复数据:
bin/mysqlbinlog --start-datetime='2011-7-7
18:0:0'--stop-datetime='2011-7-7 20:07:13' data/mysql-bin.000008
|mysql -u root
三、类型
binlog的格式有三种,这也反应了mysql的复制技术:基于SQL语句的复制(statement-based
replication, SBR),基于⾏的复制(row-based replication,
RBR),混合模式复制(mixed-based replication,
MBR)。相应地,binlog的格式也有三种:STATEMENT,ROW,MIXED。
mysql>showvariables like
'binlog_format' #查看binlog的格式
使⽤mysqlbinlog解析的binlog:
MIXED(STATEMENT):
# at 193(开始位置)
#110708 10:03:06(时间截) server id(产⽣该事件的服务id) 1 end_log_pos(⽇志的结束位置)
280 Query(事件类型) thread_id=10 exec_time=0 error_code=0
SETTIMESTAMP=1310090586;
insert into tvalues(17)
;
ROW模式:
BEGIN
;
# at 174
# at 214
#110708 10:49:22server id 1 end_log_pos
214 Table_map: `test`.`t`
mapped to number 14
#110708 10:49:22server id 1 end_log_pos
248 Write_rows: table id 14
flags: STMT_END_F
BINLOG '
MnAWThMBAAAAKAAAANYAAAAAAA4AAAAAAAEABHRlc3QAAXQAAQMAAQ==
MnAWThcBAAAAIgAAAPgAAAAAAA4AAAAAAAEAAf/+MgAAAA==
';
# at 248
#110708 10:49:22server id 1 end_log_pos
317 Query thread_id=1 exec_time=0 error_code=0
SETTIMESTAMP=1310093362;
COMMIT
STATEMENT是基于sql语句级别的binlog,每⼀条修改数据的sql都会被保存到binlog⾥;ROW是基于⾏级别的,他会记录每⼀⾏记录的变化,就是将每⼀⾏的修改都记录到binlog⾥⾯,记录的⾮常详细,但sql语句并没有在binlog⾥,在replication⾥⾯也不会因为存储过程触发器等造成Master-Slave数据不⼀致的问题,但是有个致命的缺点⽇志量⽐较⼤.由于要记录每⼀⾏的数据变化,当执⾏update语句后⾯不加where条件的时候或alter
table的时候,产⽣的⽇志量是相当的⼤。MIXED:在默认情况下是statement,但是在某些情况下会切换到row状态,如当⼀个DML更新⼀个ndb引擎表,或者是与时间⽤户相关的函数等。在主从的情况
下,在主机上如果是STATEMENT模式,那么binlog就是直接写now(),然⽽如果这样的话,那么从机进⾏操作的时间,也执⾏now(),但明显这两个时间不会是⼀样的,所以对于这种情况就必须把STATEMENT模式更改为ROW模式,因为ROW模式会直接写值⽽不是写语句(该案例是错误的,即使是STATEMENT模式也可以使⽤now()函数,具体原因以后再分析)。同样ROW模式还可以减少从机的相关计算,如在主机中存在统计写⼊等操作时,从机就可以免掉该计算把值直接写⼊从机。
四、binlog记录
每个binlog的开始都是由4个字节:fe 62 69 6e,组成的魔数(后⾯三个字节就是bin)。
然后接下来的就是⼀条记录的内容它包括:Common-Header,这部分不同版本的⼤⼩不⼀样,4.0以上的都是19个字节。在这个之后就是BODY。
Common-Header格式:(单位:字节)
Timestamp(4)
Type(1)
Server_id(4)
Total_size(4)
End_log_pos(4)
Flag(2)
Timestamp:从1970开始
Type:此log event
type如FORMAT_DESCRIPTION_EVENT、QUERY、LOAD_EVENT等,其中每个binlog的第⼀条记录的类型都是
FORMAT_DESCRIPTION_EVENT,它记录了该binlog的相关信息,如版本,这些信息对于后序分析binlog记录是有⽤的,所以对于任务要读取binlog的内容的⼯具都必须先读取第⼀条记录。QUERY包括我们经常操作的如:create,drop,update,insert等。
Server_id:创建这个事件的server id。防⽌循环主从导致的主机被从写。The master's server id
(is preserved in therelay log; used to prevent from infinite loops
in circular replication).
Total_size:该记录的⼤⼩,包括common_header及body。
End_log_pos:此下⼀条记录的开始位置。也是此条记录结束位置的上⼀个字节。
Flag:标志位。
QUERY类型的记录:
QUERY类型的记录除了开始的common-header之外,在body的开头是⼀个Post-header,然后之后才是真正的body内容。
Query Post-Header:(单位字节)
Thread_id(4)
Exec_time(4)
Db_len(1)
Error_code(2)
Status_var_len(2)
Thread_id:is used to distinguish temporary tables that belong to
differentclients.
Exec_time:The time from whenthe query started to when it was logged
in the binlog, in seconds.QUERY到达到这个binlog事件⽣成的时间间隔。
Db_len:当前数据库的名称长度。
Error_code:执⾏出错的错误号。
五、使⽤mysqlbinlog显⽰最后⼀条log
1. 使⽤脚本实现:(该脚本可以显⽰最后n条)
#!/bin/sh
#Access to the binlog's last n records
#if don't set -n, show the last record.
NUM="1"
function last_logs()
{
#get the
total records
local
rec_acc=`./bin/mysqlbinlog $1 | grep -c '^# at [0-9][0-9]*$'`
rec_acc=`expr $rec_acc - $NUM`
#Skip the
first N entries.
.
/bin/mysqlbinlog -o $rec_acc $1
}
if [ $# -lt 1 ] || [ $# -gt 3 ]
then
echo "Usage: mysqlbinlog [-n0-9] filename"
exit
elif [ $# -eq 2 ]
then
if echo $1|grep -q '^-n[0-9][0-9]*$'
then
NUM=`echo $1 | cut -d "n" -f 2`
last_logs $2
else
echo "Usage:mysqlbinlog [-n0-9] filename"
fi
else
last_logs $1
fi
此本质是⾸先利⽤mysqlbinlog binlogfile打印出所有的记录,然后通过正则表达式(^# at
[0-9][0-9]*$)判断记录个数M。最后在使⽤mysqlbinlog –o M-N
binlogfile,来显⽰最后N条。
脚本的使⽤⽅法:./last_logs –n3 binlogfile
#显⽰最后三条,不包括第⼀条FORMAT_DESCRIPTION_EVENT。
2.直接修改
上⾯的脚本必须两次扫描binlog⽂件,这对于⼤的⽂件来说消耗可能⽐较⼤。修改后的⼯具,主要利⽤的是:最后⼀条记录的end_log_pos 刚好为⽂件的⼤⼩。利⽤这个条件来判断是否需要解析打印。下⾯为主要的代码:
int is_last_flag(int &argc, char **argv)
{
if (argc == 3 && (!strcmp(argv[1],"-L") ||
!strcmp(argv[2],"-L")))
{
last_flag = 1;
if (!strcmp(argv[1],"-L"))
{
char * temp = argv[1];
argv[1] = argv[2];
argv[2] = temp;
}
//free(argv[2]);
//argv[2] = '\0';
argc--;
return 0;
}
return -1;
}
mysql连接工具struct stat file_buf;
stat(logname, &file_buf);
unsigned long file_size = (unsigned
long)file_buf.st_size;
if((ev_type != FORMAT_DESCRIPTION_EVENT)
&& last_flag && (ev->log_pos != file_size))
goto end;
其中int
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论