Ⅰ、binlog定义和作用

1.1 定义

记录每次数据库的逻辑操作(包括表结构变更和表数据修改)

包含:binlog文件和index文件

1.2 作用

  • 复制:从库读取主库binlog,本地回放实现复制
  • 备份恢复:最近逻辑备份数据+binlog实现最大可能恢复
  • innodb恢复:开启binlog的情况下,innodb事务提交是二阶段提交,发生crash的时候,innodb中事务有两种状态,一种是commit,一种是prepared,对于prepared状态的事务需要根据binlog来判断是提交还是回滚,以此来保证主从数据一致性

Ⅱ、不同类型binlog对比

- statement row mixed
说明 记录操作的SQL语句 记录每一行数据的变更 混合模式
优点 易于理解 数据一致性高、可flashback 综合上述两种模式
缺点 不支持不确定SQL语句 每张表一定要有主键 之前版本bug比较多
线上使用 不推荐 推荐 不推荐

再说一遍row

  • 优点:记录每一行记录变化,确保证主从数据严格一致性
  • 缺点:全表update,delete全表时binlog文件大,所以不建议用MySQL做类似操作

调成statement看,会发现记录的是sql语句,不说太多,线上基本上不会用

写入数据量很大时,ROW格式下,commit会比较耗时间,因为他还要写binlog( binlog在提交时才写入 )

假设更新一张几百万的表,产生的binlog可能会有几百兆,当commit时,写入的数据量就是几百兆,所以会有“阻塞”等待的效果。但其实是在写binlog到磁盘

Ⅲ、相关参数及使用命令

log_bin=bin              默认不打开,和oracle一样,不管事务大小,提交速度都一样)
log_bin_basename 设置binlog名,不设置默认为机器名,直接用上面的log_bin=bin也表示二进制文件以bin开头
binlog_format 之前为statement,5.6有几个小版本用的mixed,5.7开始默认row了
max_binlog_size 限定单个binlog文件大小,默认1G
binlog_do_db
binlog_ignore_db binlog过滤
sync_binlog 默认是0,binlog文件每次写入内容不会立刻持久化到磁盘,具体持久化是交给操作系统做,固系统崩溃会导致binlog的丢失和不一致,建议设置为1,事务写入到binlog后立即fsync到磁盘
flush binary logs; 新生成一个binlog
show master status; 查看当前的binlog

tips:

①bin.999999满了之后怎么办? 前面加1位

②binlog文件可能大于max_binlog_size,原因是一个事务产生的所有事件必须记录在同一个binlog中

Ⅳ、binlog内容

4.1 index文件

有序地记录了当前MySQL服务所使用的所用binlog文件

MySQL运行过程中千万不要骚操作修改index文件,避免出问题

4.2 binlog文件

执行show binlog events in 'xxx';

查看binlog文件内容,不指定文件默认看第一个binlog文件

(root@localhost) [test]> show binlog events;
+------------+------+----------------+-----------+-------------+--------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------+------+----------------+-----------+-------------+--------------------------------------------------+
| bin.000001 | 4 | Format_desc | 3 | 123 | Server ver: 5.7.18-log, Binlog ver: 4 |
| bin.000001 | 123 | Previous_gtids | 3 | 154 | |
| bin.000001 | 154 | Anonymous_Gtid | 3 | 219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| bin.000001 | 219 | Query | 3 | 313 | create database test |
| bin.000001 | 313 | Anonymous_Gtid | 3 | 378 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| bin.000001 | 378 | Query | 3 | 474 | use `test`; create table a (a int) |
| bin.000001 | 474 | Anonymous_Gtid | 3 | 539 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| bin.000001 | 539 | Query | 3 | 649 | use `test`; create table b (b int) engine=myisam |
| bin.000001 | 649 | Anonymous_Gtid | 3 | 714 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| bin.000001 | 714 | Query | 3 | 786 | BEGIN |
| bin.000001 | 786 | Table_map | 3 | 830 | table_id: 219 (test.a) |
| bin.000001 | 830 | Write_rows | 3 | 870 | table_id: 219 flags: STMT_END_F |
| bin.000001 | 870 | Xid | 3 | 901 | COMMIT /* xid=18 */ |
| bin.000001 | 901 | Anonymous_Gtid | 3 | 966 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| bin.000001 | 966 | Query | 3 | 1038 | BEGIN |
| bin.000001 | 1038 | Table_map | 3 | 1082 | table_id: 219 (test.a) |
| bin.000001 | 1082 | Update_rows | 3 | 1128 | table_id: 219 flags: STMT_END_F |
| bin.000001 | 1128 | Xid | 3 | 1159 | COMMIT /* xid=21 */ |
| bin.000001 | 1159 | Anonymous_Gtid | 3 | 1224 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| bin.000001 | 1224 | Query | 3 | 1296 | BEGIN |
| bin.000001 | 1296 | Table_map | 3 | 1340 | table_id: 219 (test.a) |
| bin.000001 | 1340 | Delete_rows | 3 | 1380 | table_id: 219 flags: STMT_END_F |
| bin.000001 | 1380 | Xid | 3 | 1411 | COMMIT /* xid=22 */ |
| bin.000001 | 1411 | Rotate | 3 | 1452 | bin.000002;pos=4 |
+------------+------+----------------+-----------+-------------+--------------------------------------------------+
24 rows in set (0.00 sec)

由此可见,binlog是由各类event组成,下面分析下event相关内容

field 含义
(Log_name,Pos) 一个event开始的位置信息
End_log_pos 一个event结束的位置信息
Event_type event类型

①End_log_pos - Pos = 每个event占用的字节数

②show master status; Position就代表binlog写到这个偏移量的地方,也就是写了这么多字节,即当前binlog文件的大小

③每个binlog前四个字节保留,不写数据

4.3 Event类型分析

Event_type 含义
Format_desc 一个binlog文件开始,记录server的版本号和二进制日志的版本号,5.7版本固定占119个字节
Previous_gtids/Anonymous_Gtid 5.7版本加进来的gtid
Query 开始一个sql语句
Table_map 操作的哪个库表
Write_rows 插入某条记录,具体看不到
Delete_rows 删除某条记录
Update_rows 更新某条记录
Xid 事务提交,可以看到事务号
Rotate 一个binlog文件结束,指向下一个event的起始位置(bin.xxx;pos=4)

再强调,row记录的是每条记录的情况(每次操作的每个记录记下来),而不是sql语句

Ⅴ、mysqlbinlog工具的使用

5.1 解析binlog

1、[root@VM_0_5_centos src]# mysqlbinlog bin.000001
截取一段:
# at 1224
#171107 10:17:31 server id 3 end_log_pos 1296 CRC32 0xd4d80fa6 Query thread_id=3 exec_time=0 error_code=0
SET TIMESTAMP=1510021051/*!*/;
BEGIN
/*!*/;
# at 1296
#171107 10:17:31 server id 3 end_log_pos 1340 CRC32 0x73b187fa Table_map: `test`.`a` mapped to number 219
# at 1340
#171107 10:17:31 server id 3 end_log_pos 1380 CRC32 0x2e637fcd Delete_rows: table id 219 flags: STMT_END_F BINLOG '
uxcBWhMDAAAALAAAADwFAAAAANsAAAAAAAEABHRlc3QAAWEAAQMAAfqHsXM=
uxcBWiADAAAAKAAAAGQFAAAAANsAAAAAAAEAAgAB//4CAAAAzX9jLg==
'/*!*/;
# at 1380
#171107 10:17:31 server id 3 end_log_pos 1411 CRC32 0x2a6353fd Xid = 22
COMMIT/*!*/; 这个解析出来at xxx什么的可以跟前面直接show binlog events对应起来,但是dml的内容有点小难懂,原因是为了方便传输解析出来的每行记录的内容被base64转换了 tips:
mysqlbinlog --base64-output=never xxx 非row格式下只看ddl,加密的dml不显示 2、[root@VM_0_5_centos src]# mysqlbinlog --base64-output=decode-rows -v bin.000001
row格式下可以将密文转为伪sql
同样截取一段
# at 966
#171107 10:17:23 server id 3 end_log_pos 1038 CRC32 0x00be64e0 Query thread_id=3 exec_time=0 error_code=0
SET TIMESTAMP=1510021043/*!*/;
BEGIN
/*!*/;
# at 1038
#171107 10:17:23 server id 3 end_log_pos 1082 CRC32 0x5286fd55 Table_map: `test`.`a` mapped to number 219
# at 1082
#171107 10:17:23 server id 3 end_log_pos 1128 CRC32 0x1ed2714c Update_rows: table id 219 flags: STMT_END_F
### UPDATE `test`.`a`
### WHERE
### @1=1
### SET
### @1=2
# at 1128
#171107 10:17:23 server id 3 end_log_pos 1159 CRC32 0xa254d40a Xid = 21
COMMIT/*!*/;
# at 1159
#171107 10:17:31 server id 3 end_log_pos 1224 CRC32 0x76a7413c Anonymous_GTID last_committed=5 sequence_number=6
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; 看到的是每行记录的内容,@n表示第几列
切记这搞出来的绝对不是sql语句哈,他只管你一行记录的内容,不管你的sql tips:
-vv 可以看到更详细内容,比如每个列的类型和属性,通常一个v够看
insert和delete记录一整行记录
update记录前项和后项。全表更新会导致二进制日志特别大

问题:

binlog_format设为row,只知道变化,不知道sql语句,这咋办?

解决:

设置参数binlog_rows_query_log_events=1 建议打开

再去看binlog的events,会多一个叫Rows_query的event,它会记录下改变行内容的sql

5.2 常用参数

  • 根据时间点解析
--start-datetime='xxx-xx-xx xx:xx:xx'
--stop-datetime='xxx-xx-xx xx:xx:xx'
  • 根据二进制偏移量解析
--start-position=xxx
tips:
这是从xxx来解析,那从xxx+1开始呢?会报error,从这边开始读出来不是一个完整的event,xxx-1开始也是报错,读的时候,每个evnet都有个header,如果不是标准位置就会报错 ERROR: Error in Log_event::read_log_event(): 'read error', data_len: 16640, event_type: 90
ERROR: Could not read entry at offset 1158: Error in log format or read error. --stop-position=xxx
到xxx结束,并不包含xxx这个点
特殊情况:如果指向了一个Table_map的events,会抛出了一个warning WARNING: The range of printed events ends with a row event or a table map event that does not have the STMT_END_F flag set. This might be because the last statement was not fully written to the log, or because you are using a --stop-position or --stop-datetime that refers to an event in the middle of a statement. The event(s) from the partial statement have not been written to output.

通常通过datetime找position,再来进行恢复

Ⅵ、通过mysqlbinlog恢复数据

mysqlbinlog binlog.00003 |mysql -S /tmp/mysql.sock -f
-f强制跳过错误
只恢复某一段,就加上--start-position或者--start-datetime等

官方文档:

如果存在多个二进制日志,并不建议一个一个恢复,而是用下面这个方法

mysqlbinlog binlog.[0-9]* |mysql -u root -p

一个一个恢复会报danger

说明:

如果分两次操作,会被认为在两个session中操作,如果刚好用到一个临时表,一个session退出了,另一个session上去就出错了

另一种方法:

mysqlbinlog binlog.000001 > /tmp/statements.sql
mysqlbinlog binlog.000002 >> /tmp/statements.sql
mysql -u root -p -e "source /tmp/statements.sql"

Ⅶ、清理binlog

这里介绍三种清理binlog的方法:

法1:purge
purge binary logs to 'xxx';
清理xxxbinlog文件之前的内容
purge binary logs before 'xxx'
清理xxx日期之前的内容 法2:rm
step1:MySQL停止服务
step2:按顺序rm掉binlog文件
step3:编辑index文件,将rm掉的binlog文件从index中去掉 法3:配自动清理参数
[mysqld]
expire_logs_days=N
表示只保存N天的binlog,默认值是0,表示不删除 实现原理:
当binlog文件切换或者mysql服务启动时,遍历index文件,找到第一个"最后修改时间在N天之内的文件",然后将该文件之前的所有binlog全部删除

Ⅷ、其他相关问题

8.1 增量备份怎么做

通常MySQL不做增量备份,除非单点,因为MySQL复制本身就是实时在做增量,从库开binlog,在从库上备份binlog即可(flush binary logs;产生新日志,把之前的存下来)

Oracle增量备份还是有用的,万一page发生crash,需要把所有日志重做一遍

8.2 row格式的binlog回放

一个sql插了3条记录,其实插了3次,对应3个write_rows,解析这个东西,变相执行3个sql

一个sql删了3条记录,对应的单个delete_rows,回放的时候先根据主键回放,没有主键就找一个索引来回放,如果一个索引没有,会scan全表

如果表中有10w条记录,一个索引没有,你去删全表的话,每条记录删的时候都会扫10w次,复杂度是O(10w^2)次,但因为记录越来越少,最后会扫描10w + (10w * 10w-1)/2 次,所以为什么每张表必须要有主键,这里又是一种体现,有主键回放速度会快很多,特别是delete和update

注意:没主键是不要扯什么row_id,binlog是server层的东西,和row_id没关系

tips:

①MySQL5.6推出下面这个参数来指定scan算法可以部分解决无主键表导致的复制延迟问题,其基本思路是对于在一个ROWS EVENT中的所有前镜像收集起来,然后在一次扫描全表时,判断HASH中的每一条记录进行更新

slave_rows_search_algorithms,默认值是table_scan,index_scan,另一个hash_scan可配,默认没开,也不建议用,因为创建hash表消耗比较大

②当使用innodb表时,使用rc时即使my.cnf中用的其他格式binlog也会被强制转为row

8.3 flash back

二进制日志能实现一个非常好的功能,用来挽救数据,实现flash back,oracle中还要用到undo

对于insert的event,如果要flash back,就搞成delete,delete搞成insert,update交换前后项即可

听说8.0会支持这个工具,但是现在每家互联网公司都开源自己的工具,实现flashback,但是一定要用row格式的binlog_format

8.4 binlog_cache

binlog默认写入binlog_cache中

binlog生成的过程

步骤 操作
1 binlog被write到各session对应的文件句柄缓存中,也就是标准io缓存
2 binlog从每个session私有的缓存中flush到公共缓存中,即操作系统缓存中
3 binlog从内存中sync到文件系统,持久化

第一步session之间互相看不到

第二步每个session之间互相可以看到

在这之前只要机器发生crash,则日志就相对应的丢失了

特殊情况:遇到大事务时,binlog很大,cache放不下就会落盘

(root@172.16.0.10) [(none)]> show global status like 'binlog_cache%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Binlog_cache_disk_use | 0 | -- 记录使用临时文件记录binlog日志的次数(监控项)
| Binlog_cache_use | 1 | -- 记录使用缓冲写binlog日志的次数
+-----------------------+-------+
2 rows in set (0.01 sec) (root@172.16.0.10) [(none)]> show variables like 'binlog_cache_size';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| binlog_cache_size | 32768 |
+-------------------+-------+
1 row in set (0.00 sec) 默认为32K,sessioin级的内存变量,勿设置太大
  • cache写不下落盘,然后再写binlog,就是两次写磁盘,这样会变慢。若如果参数Binlog_cache_disk_use次数很多,须考虑调大binlog_cache_size,或者检查业务中是否存在大事务(oltp场景尽量大事务拆小事务)

binlog——逻辑复制的基础的更多相关文章

  1. postgresql从库搭建--逻辑复制

    1 物理复制及逻辑复制对比 前文做了PostgreSQL物理复制的部署,其有如下主要优点 物理层面完全一致,是主要的复制方式,其类似于Oracle的DG 延迟低,事务执行过程中产生REDO recor ...

  2. MySQL复制(二)--基于二进制日志文件(binlog)配置复制

    基础环境:   主库 从库 服务器IP地址 192.168.10.11 192.168.10.12 版本 5.7.24 5.7.24 已存在的数据库 mysql> show databases; ...

  3. Windows 环境搭建 PostgreSQL 逻辑复制高可用架构数据库服务

    本文主要介绍 Windows 环境下搭建 PostgreSQL 的主从逻辑复制,关于 PostgreSQl 的相关运维文章,网络上大多都是 Linux 环境下的操作,鲜有在 Windows 环境下配置 ...

  4. verilog逻辑复制

    本文转自:http://www.cnblogs.com/linjie-swust/archive/2012/03/27/FPGA_verilog.html 在FPGA设计中经常使用到逻辑复制,逻辑复制 ...

  5. PostgreSQL逻辑复制之slony篇

    Slony是PostgreSQL领域中最广泛的复制解决方案之一.它不仅是最古老的复制实现之一,它也是一个拥有最广泛的外部工具支持的工具,比如pgAdmin3.多年来,Slony是在PostgreSQL ...

  6. PostgreSQL逻辑复制槽

    Schema | Name | Result data type | Argument data types | Type ------------+------------------------- ...

  7. PostgreSQL逻辑复制使用记录

    之前逻辑复制刚刚出来的时候就使用过,但是没有进行整理,这次一个项目需要逻辑复制的自动迁移,再次拾起逻辑复制. 在此之前有两个疑问: 1)同一个表,既有流复制,又有逻辑复制,这样数据会有两份吗? --不 ...

  8. FPGA中逻辑复制

    copy from http://www.cnblogs.com/linjie-swust/archive/2012/03/27/FPGA_verilog.html 在FPGA设计中经常使用到逻辑复制 ...

  9. PostgreSQL逻辑复制之pglogical篇

    PostgreSQL逻辑复制之slony篇 一.pglogical介绍 pglogical 是 PostgreSQL 的拓展模块, 为 PostgreSQL 数据库提供了逻辑流复制发布和订阅的功能. ...

随机推荐

  1. ANDROID 中设计模式的采用--创建型模式

     所谓模式就是在某一情景下解决某个问题的固定解决方案. 所有的创建型模式都是用作对象的创建或实例化的解决方案. 1 简单工厂模式 创建对象的最简单方法是使用new来创建一个对象,如果只创建一种固定 ...

  2. EBS 系统标准职责定义MAP

    ERP的相关职责           Responsibility Name(职责) Application(应用) Responsibility Key(关键字) Data Group(数据组) M ...

  3. RTMPdump(libRTMP) 源代码分析 5: 建立一个流媒体连接 (NetConnection部分)

    ===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...

  4. 面试之路(29)-TCP流量控制和拥塞控制-滑动窗口协议详解

    拥塞: 拥塞发生的主要原因在于网络能够提供的资源不足以满足用户的需求,这些资源包括缓存空间.链路带宽容量和中间节点的处理能力.由于互联网的设计机制导致其缺乏"接纳控制"能力,因此在 ...

  5. ANSI控制码的说明

    例如: echo -ne "\33[32m" 可以将字符的显示颜色改为绿色 echo -ne "\33[3;1H" 可以将光标移到第3行第1列处 具体的摘抄一些 ...

  6. Factor Pattern----工厂模式

    一. 概念 工厂模式就是负责生成其他对象的类或方法,就是把创建对象的过程封装起来,这样随时可以产生一个新的对象,减少代码之间耦合. 二. 使用场景(原因) 工厂模式可以将对象的生产从直接new 一个对 ...

  7. OpenLayers3的轨迹回放

    OpenLayers3实现轨迹回放需要动画操作,官网上的例子用的是postcompose,但是还可以使用javascript中setInterval和setTime. 我的例子是按官网上来的http: ...

  8. c语言 基本运算

    计算机的基本能力就是计算,所以一门程序设计语言的计算能力是非常重要的.C语言之所以无所不能,是因为它不仅有丰富的数据类型,还有强大的计算能力.C语言一共有34种运算符,包括了常见的加减乘除运算.这讲就 ...

  9. SpringBoot配置拦截器

    [配置步骤] 1.为类添加注解@Configuration,配置拦截器 2.继承WebMvcConfigurerAdapter类 3.重写addInterceptors方法,添加需要拦截的请求 @Co ...

  10. gdb命令中attach使用

    [测试程序] 我们先看看我们的测试程序: /* in eg1.c */ int wib(int no1, int no2) {         int result, diff;         di ...