首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PYTHON模拟BINLOG文件损坏 以及 解决办法

PYTHON模拟BINLOG文件损坏 以及 解决办法

原创
作者头像
大大刺猬
发布2023-03-30 11:25:16
3K0
发布2023-03-30 11:25:16
举报
文章被收录于专栏:大大刺猬大大刺猬

导读

mysql的binlog 被用来做主从, 实时备份等, 可谓非常重要(redo log你在干嘛....)

如果你经常使用Binlog的话, 你可能会遇到如下报错

ERROR: Error in Log_event::read_log_event(): 'Found invalid event in binary log', data_len: 61, event_type: 44
ERROR: Could not read entry at offset 1195: Error in log format or read error.

咋办呢? 如果是从库的话, 重建从库就行(就是比较麻烦). 如果是实时备份或者需要分析Binlog的时候 咋办呢?

PYTHON模拟binlog文件损坏

我们只需要修改event_header的某些值, 那么这个binlog文件就会被认为已经损坏了.

关于binlog的结构, 可以看我之前写的 BINLOG文件解析 这里就不再介绍了

老规矩, 本文提供的脚本在文末

拷贝一个Binlog过来

本文是模拟环境, 所以不要去修改真实环境, 就拷贝一个文件意思意思

cp -ra /data/mysql_3308/mysqllog/binlog/m3308.001014 .

执行脚本,破坏Binlog

本次只修改event_type即可, 因为多数报错都是报这个错

import binlog_tool
aa = binlog_tool.listevent('m3308.001014')  #参数为binlog文件路径
aa[14]  #查看第14个event信息

binlog_tool.mevent_type('m3308.001014',1676,66) #binlog文件名 起始pos号 修改的新的event_type值

aa = binlog_tool.listevent('m3308.001014')
aa[14] #再次确认是否修改成功

33代表GTID_LOG_EVENT
33代表GTID_LOG_EVENT

使用mysqlbinlog解析发现报错

说明我们确实破坏了binlog, 那么现在咋办呢?

event_type确实是我们刚才修改的值
event_type确实是我们刚才修改的值

解决办法

既然这个event坏了, 那我们就不要这个event了. (壮士断腕.jpg)

1. binlog_tool.listevent

如果你使用了我提供的 binlog_tool.listevent 去解析binlog的话, 你就能看到下一个event的地址(end_pos), 直接指定从下一个地址开始即可

mysqlbinlog --start-position=1737 m3308.001014 >/dev/null #本次实验是1737

然后把两次解析的结果拼起来就行. (之前报错的时候, 前面部分是解析正常的)

一个个POS号往后加

如果你没有使用我给的工具的话, 你就的自己一个个pos号往后试了 -_-

虽然麻烦点, 但也能用....
虽然麻烦点, 但也能用....

总结

binlog损坏的场景并不常见(sync_binlog=1的环境,binlog写失败事务就回滚了), 但是遇到了还是得有解决的办法才行.

1. 跳过有问题的event 可能会丢数据. 不过本次有问题的event是gtid, 所以不会丢数据

2. sync_binlog设置为1很重要. 起码你最多就丢一个事务.

3. 会一门编程语言,对dba运维好处很大. 能解决很多问题.

附源码

其实我还给了个read_event的函数, 方便你去分析有问题的那个event. 只不过本文未演示而已

import struct
import os

def listevent(filename='m3308.001014',):
	el = []
	with open(filename,'rb') as f:
		magic = f.read(4)
		if magic != b'\xfebin':
			return []
		while True:
			header = f.read(19)
			if len(header) == 19:
				timestamp, event_type, server_id, event_size, log_pos, flags = struct.unpack("<LBLLLh",header[0:19])
				el.append({'timestamp':timestamp,'start_pos':f.tell()-19,'end_pos':log_pos,'size':event_size,'event_type':event_type})
				event_body = f.read(event_size-19)
			else:
				print('endsize:',f.tell(),'event_count',len(el))
				break
		return el

def mevent_type(filename='m3308.001014',start_pos=4,new_value=250):
	f = os.open(filename, os.O_RDWR|os.O_CREAT, 0o644)
	os.lseek(f, start_pos+4, 0)
	os.write(f, struct.pack('<B',new_value)) 
	os.close(f)
	return True

def read_event(filename='m3308.001014',start_pos=4,max_size=100000):
	with open(filename,'rb') as f:
		f.seek(start_pos,0)
		header = f.read(19)
		timestamp, event_type, server_id, event_size, log_pos, flags = struct.unpack("<LBLLLh",header[0:19])
		if event_size < max_size:
			event_body = f.read(event_size-19)
			return {'timestamp':timestamp,'event_type':event_type,'server_id':server_id,'event_size':event_size,'log_pos':log_pos,'flags':flags,'event_body':event_body}
		else:
			return None

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • PYTHON模拟binlog文件损坏
    • 拷贝一个Binlog过来
      • 执行脚本,破坏Binlog
        • 使用mysqlbinlog解析发现报错
        • 解决办法
          • 1. binlog_tool.listevent
            • 一个个POS号往后加
            • 总结
            • 附源码
            相关产品与服务
            云数据库 MySQL
            腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
            http://www.vxiaotou.com