MySQL复制 -- binlog(2)
MySQL复制是使用最为广泛的一套组建,上一节已经简单说了一下复制的一些用途和复制的原理,知道了这些我们能够快速的搭建起复制的平台,但是仅知道这些还是不够的,很多时候并不是一帆风顺的,总会有那么一小段时间,或者总会有那么几次会出现各种各样的问题。当出现问题我们应该怎么去解决呢?
下面我们先来看看MySQL复制常见的一些问题,以及对应的解决办法;更进一步的我们是否可以考虑做的更好,提供自动化或者半自动化的工具来帮助我们更快更好的解决问题呢?
OK,首先我们先来看看我们经常在复制中会遇到的问题吧。
其中最经典的两个错误,也是比较麻烦的两个:
ErrorNo |
描述 |
通常解决办法 |
1062 |
由于主键或者唯一建冲突导致的 |
可以把从库上这个记录删掉 |
1032 |
找不到记录 |
解析Binlog前项,补气记录 |
现在问题来了, 我们现在已经知道了这种问题出现的原因,也知道了如何去应对这种问题。那么要是这种问题经常发生怎么办呢?业务对备库有比较强的依赖,又该怎么办呢?
我们的想法是能不能做个自动或者半自动的工具或者脚步来帮助我们去及时的发现问题并解决问题。仔细想想如果要做这件事情,那么我们首先要做的事情就是怎样正确的找到这条记录,然后怎么去删除掉也好,或者补起前项也好。这是我们要做的事情,找到这些记录后我们就可以 restart slave ;然后复制就可以正常工作了。
再如何找到这些个记录之前我们要结合前面的内容,并开始更进一步的认识binlog(ROW 格式的binlog):
首先每个Event 有 event_header 事件头:
事件头有19个字节,时间戳占4个字节,事件类型1个字节,服务器ID4个字节,事件长度4个字节,下个事件开始位置4个字节以及2个字节的标志位,通俗一点就是:
+---------+---------+---------+------------+-----------+-------+
|timestamp|type code|server_id|event_length|end_log_pos|flags |
|4 bytes |1 byte |4 bytes |4 bytes |4 bytes |2 bytes |
+---------+---------+---------+------------+-----------+-------+
关于事件类型请看 binlog_event.h#245 行开始有个枚举类型:
我这里有个 5.7.6 版本的事件头信息,由于这个版本event_type比较多(39个), 我们暂且先关注一下:
ROTATE_EVENT= 4,
FORMAT_DESCRIPTION_EVENT= 15,
TABLE_MAP_EVENT = 19,
WRITE_ROWS_EVENT = 30,
UPDATE_ROWS_EVENT = 31,
DELETE_ROWS_EVENT = 32,
然后每个 Event 都会有 event_body 事件体:
事件体由三部分组成: header、post-header、payload 组成,不过通常我们把 post-header 和 payload 都归结成为事件体,实际上 post-header 存放的是一些定长的数据,我们平常就不需要特别的care。
所以通俗版的事件体我们描述如下:
+=====================================+
| event | fixed part (post-header) |
| data +-------------------------------------------------------+
| | variable part (payload) |
+=====================================+
我们之所以说 post-header 是定长的, 就是因为在 format description event 事件中,对于这个长度已经规定好了。也就是在文件开始的第一个event 里边规定的。
最后一个事件是 rotat event 日志轮换事件:
通过前面我们知道 ROTATE_EVENT 的 type_code 是 4,其 那么 post-header 长度 8。
OK, 这些基本信息我们都知道了, 那么接下来我们就开始写个程序解析我们的binlog吧,让我们的程序在处理复制是助我们一臂之力!
关于如何解析我放到下一节吧,内容有点多 ,再写在这里也不太合适了。
附:
EventHeader 描述: https://dev.mysql.com/doc/internals/en/event-header-fields.html