首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >mysql redo解析(72种mlog)

mysql redo解析(72种mlog)

原创
作者头像
大大刺猬
发布2026-02-27 15:30:11
发布2026-02-27 15:30:11
280
举报
文章被收录于专栏:大大刺猬大大刺猬

导读

之前讲了mysql恢复drop/truncate表的方法, 但对于8.0的truncate却比较麻烦, 主要是indexid不好确认, 当时提示了下可以找redo.

其实update操作是不写之前的信息到redo的, 但是要将update前的信息写到undo, 而写undo的过程是要记录redo的, 所以我们还是可以解析redo获取到update之前的操作(即找到被truncate的表).

3年前,我们有解析过redo,虽然比较简单. 这次我们来补全下,顺便整个redoreader工具来解析mysql redo log, 考虑到还有不少使用5.7的, 所以我们兼容5.7,8.0等版本.

redo

一个事务由若干条SQL组成, 一条SQL由若干个mtr(mini-transaction)组成, 一个mtr由若干个mlog组成. 若干个mlog放在若干个block里面. 若干个block组成一个redo log file, 若干个redo log file构成redo(group).

8.0.30之前redo文件是循环写的, 8.0.30及其之后是32个redo文件构成一个组的. 简单点理解就是由几个循环写的redo文件变成了一堆redo文件. 之前的版本是只有0号redolog才有log header,由于log header会记录一些关键信息, 所以会经常写(可观察其时间戳), 后面的版本是每个都有,类似binlog那种了

一图以言之:

这里的校验(LOG_BLOCK_CHECKSUM)是使用的crc32c算法(innodb的校验基本上都是用的这玩意.)

mlog

来看看具体的mlog, 先看下整体结构:

对象

大小(字节)

描述

mlog_type

1 字节

第1bit记录是否是单个mlog作为mtr,后7bit就是事务类型

spaceno

mach_parse_compressed

操作的表空间号

pageno

mach_parse_compressed

操作的表空间的页号

data

n

不同的mlog有不同的data,也是本文的重点之一.

spaceno和pageno是大部分mlog都有的, 但MLOG_MULTI_REC_END,MLOG_TABLE_DYNAMIC_META,MLOG_CHECKPOINT是不需要的,也就没有

一共有1-76(不含3,5,6,7,12)即72种mlog. 我们全都解析! 我们主要参考源码中的函数recv_parse_or_apply_log_rec_body(storage/innobase/log/log0recv.cc)

由于mtr太多,每个都拎出来的话,看起比较烦,我就直接整个表格吧: 带有8027的表示老版本使用的,新版本结构发生了变化.

mlog编号

mlog类型

mlog结构

描述

1

MLOG_1BYTE

mlog_parse_nbytes

记录1字节的修改

2

MLOG_2BYTES

mlog_parse_nbytes

记录2字节的修改

4

MLOG_4BYTES

mlog_parse_nbytes

记录4字节的修改

8

MLOG_8BYTES

mlog_parse_nbytes

记录8字节的修改

9

MLOG_REC_INSERT_8027

parse_index_8027(False) page_cur_parse_insert_rec

记录insert操作的

10

MLOG_REC_CLUST_DELETE_MARK_8027

parse_index_8027(False) btr_cur_parse_del_mark_set_clust_rec

对主键索引的某行做delete标记

11

MLOG_REC_SEC_DELETE_MARK

value:1字节 offset:2字节

对二级索引的某行做delete标记

13

MLOG_REC_UPDATE_IN_PLACE_8027

parse_index_8027(False) btr_cur_parse_update_in_place

update of a record, preserves record field sizes

14

MLOG_REC_DELETE_8027

parse_index_8027(False) page_cur_parse_delete_rec

delete一行

15

MLOG_LIST_END_DELETE_8027

parse_index_8027(False) offset:2字节

delete一行(结束标记)

16

MLOG_LIST_START_DELETE_8027

parse_index_8027(False) page_parse_delete_rec_list

delete一行(开始标记)

17

MLOG_LIST_END_COPY_CREATED_8027

parse_index_8027(False) page_parse_copy_rec_list_to_created_page

Copy record list end to a new created index page

18

MLOG_PAGE_REORGANIZE_8027

parse_index_8027(False) btr_parse_page_reorganize(False)

重建索引(row_format=REDUNDANT)

19

MLOG_PAGE_CREATE

创建一个索引页

20

MLOG_UNDO_INSERT

undo_len:2字节 undo_data:undo_len

写undo(我们恢复truncate表就看这个)

21

MLOG_UNDO_ERASE_END

erase an undo log page end

22

MLOG_UNDO_INIT

type:mach_parse_compressed

初始化undo页

23

MLOG_UNDO_HDR_DISCARD

discard an update undo log header

24

MLOG_UNDO_HDR_REUSE

trx_id:mach_u64_parse_compressed

reuse an insert undo log header

25

MLOG_UNDO_HDR_CREATE

trx_id:mach_u64_parse_compressed

创建一个undo log header

26

MLOG_REC_MIN_MARK

rec:2字节

定义一个最小字段

27

MLOG_IBUF_BITMAP_INIT

初始化一个ibuf bitmap页

28

MLOG_LSN

mtr_header

记录当前的lsn

29

MLOG_INIT_FILE_PAGE

30

MLOG_WRITE_STRING

offset:2 length:2 data:length

写一个字符串

31

MLOG_MULTI_REC_END

一个mtr结束的mlog

32

MLOG_DUMMY_RECORD

dummy log record used to pad a log block full

33

MLOG_FILE_CREATE

flags:4 filename_len:2 filename:filename_len

log record about an .ibd file creation

34

MLOG_FILE_RENAME

from_len:2 from_name:from_len to_len:2 to_name:to_len

rename databasename/tablename

35

MLOG_FILE_DELETE

filename_len:2 filename:filename_len

删除一个表空间文件

36

MLOG_COMP_REC_MIN_MARK

rec:2

定义一个最小字段(compact)

37

MLOG_COMP_PAGE_CREATE

创建一个索引页(compact)

38

MLOG_COMP_REC_INSERT_8027

parse_index_8027(True) page_cur_parse_insert_rec

记录insert操作的(compact)

39

MLOG_COMP_REC_CLUST_DELETE_MARK_8027

parse_index_8027(True) btr_cur_parse_del_mark_set_clust_rec

对主键索引的某行做delete标记(compact)

40

MLOG_COMP_REC_SEC_DELETE_MARK

parse_index_8027(True)

对二级索引的某行做delete标记(compact)

41

MLOG_COMP_REC_UPDATE_IN_PLACE_8027

parse_index_8027(True) btr_cur_parse_update_in_place

update(compact)

42

MLOG_COMP_REC_DELETE_8027

parse_index_8027(True) page_cur_parse_delete_rec

delete(compact)

43

MLOG_COMP_LIST_END_DELETE_8027

parse_index_8027(True) page_parse_delete_rec_lis

delete结束(compact)

44

MLOG_COMP_LIST_START_DELETE_8027

parse_index_8027(True) page_parse_delete_rec_list

delete开始(compact)

45

MLOG_COMP_LIST_END_COPY_CREATED_8027

parse_index_8027(True) page_parse_copy_rec_list_to_created_page

copy compact record list end to a new created index page

46

MLOG_COMP_PAGE_REORGANIZE_8027

parse_index_8027(True) btr_parse_page_reorganize(False)

reorganize an index page

47

MLOG_FILE_CREATE2

fil_name_parse

创建一个ibd文件

48

MLOG_ZIP_WRITE_NODE_PTR

offset:2字节 z_offset:2字节 data:4字节

节点指针(压缩的非叶子节点)

49

MLOG_ZIP_WRITE_BLOB_PTR

offset:2字节 z_offset:2字节 data:20字节

压缩的溢出页指针

50

MLOG_ZIP_WRITE_HEADER

offset:1 len:1 data:len

压缩页页头

51

MLOG_ZIP_PAGE_COMPRESS

page_size:2 trailer_size:2 page_pre:4 page_next:4 page_data:page_size trailer_data:trailer_size

压缩一个索引页

52

MLOG_ZIP_PAGE_COMPRESS_NO_DATA_8027

parse_index_8027(True) page_zip_parse_compress_no_data

压缩一个索引页(nodata)

53

MLOG_ZIP_PAGE_REORGANIZE_8027

parse_index_8027(True) btr_parse_page_reorganize(True)

重建一个压缩页

54

MLOG_FILE_RENAME2

fil_name_parse

重命名一个表空间文件

55

MLOG_FILE_NAME

fil_name_parse

note the first use of a tablespace file since checkpoint

56

MLOG_CHECKPOINT

lsn:8

lsn

57

MLOG_PAGE_CREATE_RTREE

创建一个Rtree索引页

58

MLOG_COMP_PAGE_CREATE_RTREE

创建一个Rtree索引页(compact)

59

MLOG_INIT_FILE_PAGE2

MLOG_INIT_FILE_PAGE

60

MLOG_TRUNCATE

lsn:8

Disabled for WL6378

61

MLOG_INDEX_LOAD

data:8

62

MLOG_TABLE_DYNAMIC_META

tableid:mach_parse_u64_much_compressed version:mach_parse_u64_much_compressed persister:1 autoinc:mach_parse_u64_much_compressed

持久化动态元数据信息 注:这个及其之后的Mlog是8.0才有的

63

MLOG_PAGE_CREATE_SDI

创建一个sdi索引页

64

MLOG_COMP_PAGE_CREATE_SDI

创建一个sdi索引页(compact)

65

MLOG_FILE_EXTEND

offset:8 size:8

扩展表空间

66

MLOG_TEST

key:8 value:8 payload_size:2 payload:payload_size start_lsn:8 end_lsn:8

tests of redo log.

67

MLOG_REC_INSERT

parse_index page_cur_parse_insert_rec(False)

68

MLOG_REC_CLUST_DELETE_MARK

parse_index btr_cur_parse_del_mark_set_clust_rec

69

MLOG_REC_DELETE

parse_index offset:2

70

MLOG_REC_UPDATE_IN_PLACE

parse_index btr_cur_parse_update_in_place

71

MLOG_LIST_END_COPY_CREATED

parse_index log_data_len:4 data:log_data_len

72

MLOG_PAGE_REORGANIZE

parse_index level:0(固定6)

73

MLOG_ZIP_PAGE_REORGANIZE

parse_index btr_parse_page_reorganize(True)

74

MLOG_ZIP_PAGE_COMPRESS_NO_DATA

parse_index page_zip_parse_compress_no_data

75

MLOG_LIST_END_DELETE

parse_index offset:2

76

MLOG_LIST_START_DELETE

parse_index offset:2

看起来多, 实际上就那么几种,很多都是新版本(instant)改了一丢丢, 旧版本就多个compact之类的.

再通过之前的ibd学习, 看到这些mlog就会格外的亲切.

mlog基础结构

对于spaceno,pageno等会大量出现,而且大部分都是固定的,为了节省空间,就需要对其进行简单的"压缩"处理(系统表空间id也经常使用,所以压缩的时候也得考虑这个)

上面有一堆比较通用的结构,我们这里来一个个瞅一下:

parse_index

8.0使用的解析index信息的

对象

大小(字节)

index_version

1

index_flags

1

cols

2

inst_cols

2 (if index_flags&0x04)

n_uniq

2

index_fields

2*cols

index_versioned_fields

2*inst_cols

老版本的解析index(compact)则为:

parse_index_8027

对象

大小(字节)

n

2

n

2 (if n & 0x8000)

n_uniq

2

col

2*n

来看下insert操作需要的:

page_cur_parse_insert_rec

对象

大小(字节)

offset

1 (if not is_short)

end_seg_len

mach_parse_compressed

info_and_status_bits

1 (if end_seg_len & 0x1)

origin_offset

mach_parse_compressed (if end_seg_len & 0x1)

mismatch_index

mach_parse_compressed (if end_seg_len & 0x1)

data

end_seg_len

delete操作基本上就是一个offset:

page_cur_parse_delete_rec

对象

大小(字节)

offset

2

copy record操作:

page_parse_copy_rec_list_to_created_page

对象

大小(字节)

log_data_len

4

data

log_data_len

delete操作(起始/结束):

page_parse_delete_rec_list

对象

大小(字节)

offset

2

重建page的操作

btr_parse_page_reorganize

对象

大小(字节)

level

2 (如果压缩的话)

主键索引标记delete

btr_cur_parse_del_mark_set_clust_rec

对象

大小(字节)

flags

1

val

1

pos

mach_parse_compressed

roll_ptr

7

trx_id

mach_u64_parse_compressed

offset

2

update操作:

btr_cur_parse_update_in_place

对象

大小(字节)

flags

1

pos

mach_parse_compressed

roll_ptr

7

trx_id

mach_u64_parse_compressed

rec_offset

2

info_bits

1

n_fields

mach_parse_compressed

field_no

mach_parse_compressed*n_fields

field_len

mach_parse_compressed*n_fields

field_value

field_len*n_fields

压缩一个索引页

page_zip_parse_compress_no_data

对象

大小(字节)

level

1

文件相关的操作:

fil_name_parse

对象

大小(字节)

4(if MLOG_FILE_CREATE2)

len

2

name

len

new_len

2 (if MLOG_FILE_RENAME2)

new_name

new_len (if MLOG_FILE_RENAME2)

感觉使用python表示更直观一些, 但可能就比较水了...

mlog压缩方式

对于经常出现的spaceno,pageno等整形是可以简单压缩下的(节省空间). 如果只是按照类似连接协议那种方式的压缩的话, 那么undo(4294967279),mysql.ibd(4294967294)就得使用老长的空间了. 所以采取了折中的压缩方式: 对小/大的数字采用短一点的编码. 说起来比较复杂, 我们直接使用python代码来表示4字节以内的压缩方式吧:

代码语言:python
复制
def rmach_parse_compressed(data):
	val = data[0]
	n = 1
	if val < 0x80:
		n = 1
	elif val < 0xC0:
		val = struct.unpack('>H',data[:2])[0] & 0x3FFF
		n = 2
	elif val < 0xE0:
		val = struct.unpack('>L',b'\x00'+data[:3])[0] & 0x1FFFFF
		n = 3
	elif val < 0xF0:
		val = struct.unpack('>L',data[:4])[0] & 0xFFFFFFF
		n = 4
	elif val < 0xF8:
		val = struct.unpack('>L',data[1:5])[0]
		n = 5
	elif val < 0xFC:
		val = (struct.unpack('>H',data[:2])[0] & 0x3FF) | 0xFFFFFC00
		n = 2
	elif val < 0xFE:
		val = (struct.unpack('>L',b'\x00'+data[:3])[0] & 0x1FFFF) | 0xFFFE0000
		n = 3
	else:
		val = (struct.unpack('>L',b'\x00'+data[1:4]))[0] | 0xFF000000
		n = 4
	return n,val

也就是使用1-5字节来表示4字节的数字. 有了4字节的数字, 那么8字节的就简单了:

8字节的压缩有2种方式:

mach_u64_parse_compressed: 即对前4字节采取4字节压缩方式(mach_parse_compressed), 后4字节不变, 这样就是使用5-9字节表示8字节..

代码语言:python
复制
        def mach_u64_parse_compressed(self):
                return (self.mach_read_next_compressed()<<32)|self.mach_read_from_n(4)

mach_parse_u64_much_compressed: 如果第1字节是0xff则直接使用mach_parse_compressed. 否则前后4字节都使用mach_parse_compressed来表示. 就只有MLOG_TABLE_DYNAMIC_META在使用...

代码语言:python
复制
        def mach_parse_u64_much_compressed(self):
                if self.offset == 508: # 可能跨Block
                        self._read_block()
                        self.offset = 12
                if self.data[self.offset] != 0xFF:
                        return self.mach_parse_compressed()
                n = self.mach_parse_compressed()
                n << 32
                return n|self.mach_parse_compressed()

redo_reader 实战

讲了那么多理论. 我们来动动手. 于是很快就写了个redo_reader: https://github.com/ddcw/redo

下载

代码语言:shell
复制
wget https://github.com/ddcw/redo/archive/refs/heads/main.zip
unzip main.zip
cd redo-main/
python3 redo_reader.py --help

使用场景

我们想看某条SQL语句执行的时候,redo进行了哪些操作:

获取起止LSN: (尽量保证只有你的SQL在跑,不然干扰太多)

代码语言:sql
复制
-- 查看当前LSN
show engine innodb status\G

-- 执行任意SQL
insert into db1.t20260227 values(1);

-- 查看当前LSN
show engine innodb status\G

然后解析对应的redo log(不知道是哪个的话, 看时间戳就是了.或者直接*)

代码语言:shell
复制
python3 redo_reader.py /data/mysql_8037/mysqllog/redolog/#innodb_redo/#ib_redo40 --start-lsn 674459317 --stop-lsn 674460135

虽然只是简单的insert,但输出内容是非常多的,(truncate更多). 详情如下:

代码语言:txt
复制
[root@ddcw21 redo-main]#python3 redo_reader.py /data/mysql_8037/mysqllog/redolog/#innodb_redo/#ib_redo40 --start-lsn 674459317 --stop-lsn 674460135

- [M] file:#ib_redo40 gblockno:1317304 lsn:674459317 cblockno:6731 offset:181 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 30
    offset    : 50
    value     : 4294967295

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459325 cblockno:6731 offset:189 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 30
    offset    : 54
    value     : 0

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459332 cblockno:6731 offset:196 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 30
    offset    : 56
    value     : 4294967295

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459340 cblockno:6731 offset:204 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 30
    offset    : 60
    value     : 0

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459347 cblockno:6731 offset:211 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 30
    offset    : 46
    value     : 0

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459354 cblockno:6731 offset:218 name:MLOG_MULTI_REC_END(31)
    spaceno   : -1
    pageno    : -1

- [S] file:#ib_redo40 gblockno:1317304 lsn:674459355 cblockno:6731 offset:219 name:MLOG_8BYTES(8)
    spaceno   : 0
    pageno    : 7
    offset    : 38
    value     : 12288

- [M] file:#ib_redo40 gblockno:1317304 lsn:674459365 cblockno:6731 offset:229 name:MLOG_UNDO_HDR_REUSE(24)
    spaceno   : 4294967278
    pageno    : 146
    trx_id    : 16715

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459375 cblockno:6731 offset:239 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 40
    value     : 272

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459384 cblockno:6731 offset:248 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 42
    value     : 272

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459393 cblockno:6731 offset:257 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 104
    value     : 272

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459402 cblockno:6731 offset:266 name:MLOG_MULTI_REC_END(31)
    spaceno   : -1
    pageno    : -1

- [S] file:#ib_redo40 gblockno:1317304 lsn:674459403 cblockno:6731 offset:267 name:MLOG_UNDO_INSERT(20)
    spaceno   : 4294967278
    pageno    : 146
    len       : 11
    data      : b'\x0b\x00\x84\xd7\x06\x00\x00\x00\x000\x00'

- [S] file:#ib_redo40 gblockno:1317304 lsn:674459421 cblockno:6731 offset:285 name:MLOG_REC_INSERT(67)
    spaceno   : 177
    pageno    : 4
    index_version: 1
    index_flags: 1
    cols      : 4
    inst_cols : None
    n_uniq    : 1
    index_fields: [32774, 32774, 32775, 4]
    index_versioned_fields: None
    offset    : 99
    end_seg_len: 29
    info_and_status_bits: 0
    origin_offset: 6
    mismatch_index: 0
    data      : b'\x00\x00\x00\x10\xff\xf2\x00\x00\x00\x000\x00\x00\x00\x00\x00AK\x82\x00\x00\x00\x92\x01\x10\x80\x00\x00\x01'

- [M] file:#ib_redo40 gblockno:1317304 lsn:674459474 cblockno:6731 offset:338 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 56
    value     : 6

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459482 cblockno:6731 offset:346 name:MLOG_1BYTE(1)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 106
    value     : 1

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459490 cblockno:6731 offset:354 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 132
    value     : 1

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459498 cblockno:6731 offset:362 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 136
    value     : 24

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459506 cblockno:6731 offset:370 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 140
    value     : 0

  [M] file:#ib_redo40 gblockno:1317304 lsn:674459514 cblockno:6731 offset:378 name:MLOG_WRITE_STRING(30)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 144
    length    : 128
    data      : b'MySQLXid%\xa9\xb0\x19\x00\x00\x00\x00Q\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459667 cblockno:6732 offset:019 name:MLOG_MULTI_REC_END(31)
    spaceno   : -1
    pageno    : -1

- [M] file:#ib_redo40 gblockno:1317305 lsn:674459668 cblockno:6732 offset:020 name:MLOG_UNDO_HDR_CREATE(25)
    spaceno   : 4294967278
    pageno    : 293
    trx_id    : 16715

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459678 cblockno:6732 offset:030 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 40
    value     : 3578

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459687 cblockno:6732 offset:039 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 42
    value     : 3578

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459696 cblockno:6732 offset:048 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3345
    value     : 3578

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459705 cblockno:6732 offset:057 name:MLOG_MULTI_REC_END(31)
    spaceno   : -1
    pageno    : -1

- [M] file:#ib_redo40 gblockno:1317305 lsn:674459706 cblockno:6732 offset:058 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 146
    offset    : 56
    value     : 2

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459714 cblockno:6732 offset:066 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 56
    value     : 2

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459722 cblockno:6732 offset:074 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 34
    offset    : 50
    value     : 293

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459730 cblockno:6732 offset:082 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 34
    offset    : 54
    value     : 3361

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459738 cblockno:6732 offset:090 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 34
    offset    : 56
    value     : 293

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459746 cblockno:6732 offset:098 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 34
    offset    : 60
    value     : 3361

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459754 cblockno:6732 offset:106 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3361
    value     : 4294967295

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459763 cblockno:6732 offset:115 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3365
    value     : 0

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459771 cblockno:6732 offset:123 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3367
    value     : 4294967295

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459780 cblockno:6732 offset:132 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3371
    value     : 0

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459788 cblockno:6732 offset:140 name:MLOG_4BYTES(4)
    spaceno   : 4294967278
    pageno    : 34
    offset    : 46
    value     : 1

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459795 cblockno:6732 offset:147 name:MLOG_8BYTES(8)
    spaceno   : 4294967278
    pageno    : 34
    offset    : 4168
    value     : 16716

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459806 cblockno:6732 offset:158 name:MLOG_8BYTES(8)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3335
    value     : 16716

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459818 cblockno:6732 offset:170 name:MLOG_2BYTES(2)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3343
    value     : 0

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459826 cblockno:6732 offset:178 name:MLOG_1BYTE(1)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3513
    value     : 1

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459834 cblockno:6732 offset:186 name:MLOG_WRITE_STRING(30)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3514
    length    : 64
    data      : b'de98b78e-dbb5-11f0-9e1b-000c2980c11e:379\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459907 cblockno:6732 offset:259 name:MLOG_1BYTE(1)
    spaceno   : 4294967278
    pageno    : 293
    offset    : 3347
    value     : 3

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459915 cblockno:6732 offset:267 name:MLOG_MULTI_REC_END(31)
    spaceno   : -1
    pageno    : -1

- [M] file:#ib_redo40 gblockno:1317305 lsn:674459916 cblockno:6732 offset:268 name:MLOG_UNDO_HDR_REUSE(24)
    spaceno   : 4294967279
    pageno    : 147
    trx_id    : 16717

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459926 cblockno:6732 offset:278 name:MLOG_2BYTES(2)
    spaceno   : 4294967279
    pageno    : 147
    offset    : 40
    value     : 272

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459935 cblockno:6732 offset:287 name:MLOG_2BYTES(2)
    spaceno   : 4294967279
    pageno    : 147
    offset    : 42
    value     : 272

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459944 cblockno:6732 offset:296 name:MLOG_2BYTES(2)
    spaceno   : 4294967279
    pageno    : 147
    offset    : 104
    value     : 272

  [M] file:#ib_redo40 gblockno:1317305 lsn:674459953 cblockno:6732 offset:305 name:MLOG_MULTI_REC_END(31)
    spaceno   : -1
    pageno    : -1

- [S] file:#ib_redo40 gblockno:1317305 lsn:674459954 cblockno:6732 offset:306 name:MLOG_UNDO_INSERT(20)
    spaceno   : 4294967279
    pageno    : 147
    len       : 50
    data      : b'\x0b\x00\x84\x1a$de98b78e-dbb5-11f0-9e1b-000c2980c11e\x08\x80\x00\x00\x00\x00\x00\x01{'

- [S] file:#ib_redo40 gblockno:1317305 lsn:674460011 cblockno:6732 offset:363 name:MLOG_REC_INSERT(67)
    spaceno   : 4294967294
    pageno    : 590
    index_version: 1
    index_flags: 1
    cols      : 5
    inst_cols : None
    n_uniq    : 2
    index_fields: [32768, 32776, 32774, 32775, 32776]
    index_versioned_fields: None
    offset    : 2540
    end_seg_len: 71
    info_and_status_bits: -1
    origin_offset: -1
    mismatch_index: -1
    data      : b'$\x00\x01H\xf5!de98b78e-dbb5-11f0-9e1b-000c2980c11e\x80\x00\x00\x00\x00\x00\x01{\x00\x00\x00\x00AM\x81\x00\x00\x00\x93\x01\x10\x80\x00\x00\x00\x00\x00\x01{'

- [S] file:#ib_redo40 gblockno:1317305 lsn:674460107 cblockno:6732 offset:459 name:MLOG_2BYTES(2)
    spaceno   : 4294967279
    pageno    : 147
    offset    : 56
    value     : 2

- [S] file:#ib_redo40 gblockno:1317305 lsn:674460115 cblockno:6732 offset:467 name:MLOG_8BYTES(8)
    spaceno   : 0
    pageno    : 5
    offset    : 15908
    value     : 16717

- [S] file:#ib_redo40 gblockno:1317305 lsn:674460125 cblockno:6732 offset:477 name:MLOG_8BYTES(8)
    spaceno   : 0
    pageno    : 5
    offset    : 15908
    value     : 16718

输出这么大一堆, 其实关键的就是:

代码语言:txt
复制
- [S] file:#ib_redo40 gblockno:1317304 lsn:674459421 cblockno:6731 offset:285 name:MLOG_REC_INSERT(67)
    spaceno   : 177
    pageno    : 4
    index_version: 1
    index_flags: 1
    cols      : 4
    inst_cols : None
    n_uniq    : 1
    index_fields: [32774, 32774, 32775, 4]
    index_versioned_fields: None
    offset    : 99
    end_seg_len: 29
    info_and_status_bits: 0
    origin_offset: 6
    mismatch_index: 0
    data      : b'\x00\x00\x00\x10\xff\xf2\x00\x00\x00\x000\x00\x00\x00\x00\x00AK\x82\x00\x00\x00\x92\x01\x10\x80\x00\x00\x01'

这个data就是实际insert的内容, 一共29字节,

null_bitmask 1 字节

record_header: 5 字节

rowid: 6字节

trxid+rollptr: 13字节

id: 4字节

我们也可以打开ibd文件确认确认:

其它SQL对应的redo信息就请自己去解析吧, 这玩意内容太多了. 还可以在人工去看对应的表空间的对应page验证

由于输出内容太多, 所以我们还加了个过滤功能: 比如查看指定的mlog.

比如

查看truncate table的indexid

有2种方法:

  1. 直接查看redo的MLOG_UNDO_INSERT (把update前的内容insert到undo里面去)
  2. 根据redo记录的MLOG_REC_UPDATE_IN_PLACE的rollptr去找undo信息

方法1:

代码语言:shell
复制
python3 redo_reader.py /data/mysql_8037/mysqllog/redolog/#innodb_redo/#ib_redo40 --start-lsn 674460189 --set name=MLOG_UNDO_INSERT | strings |grep ';space_id'

看到的id=398就是被truncate表的indexid.有了这玩意我们就能使用ibd2sql去扫描磁盘恢复被truncate表了.

方法2:

代码语言:shell
复制
python3 redo_reader.py /data/mysql_8037/mysqllog/redolog/#innodb_redo/#ib_redo40 --start-lsn 674460189 --set name=MLOG_REC_UPDATE_IN_PLACE | strings |grep ';space_id' -B 17

这个id=399是新的indexid,旧的我们得根据roll_ptr去undo里面找:

代码语言:shell
复制
python3 undo_reader.py /data/mysql_8037/mysqldata/undo_001 -r 281475001813712

这里解析出来的id=398就是我们truncate表的indexid了(删除之前忘记查看原来是多少了....)

总结

mysql的redo记录的是物理+逻辑日志.结构比较简单(复杂了性能就是个问题), 我们能解析mysql redo文件了, 能了解到各SQL对应的具体的内部操作了, 其实再进一步就能做个类似xbk的热备工具了(-_-)

我们这里只解析了2条SQL, 其它SQL对应的redo操作请读者自行验证.

参考:

https://dev.mysql.com/doc/refman/8.0/en/innodb-init-startup-configuration.html

https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_INNODB_REDO_LOG_FORMAT.html

https://github.com/ddcw/redo

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • redo
    • mlog
    • mlog基础结构
    • mlog压缩方式
  • redo_reader 实战
    • 下载
    • 使用场景
    • 查看truncate table的indexid
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档