binlog浅析

一、基础知识

什么是binlog?

(图一)

全称:Binary Log (二进制日志),包含描述数据库更改的“ 事件 ”,例如表创建操作或对表数据的更改。二进制日志不用于诸如select或 show不修改数据的语句 。要记录所有语句(例如,标识问题查询),请使用常规查询日志。

在哪里产生的?

我们都知道MYSQL有两层结构,第一层:server层,里面包含连接器、查询缓存、解析器、优化器、执行器,第二次是存储引擎层,例如:InnoDB、MyISAM、Memory 等多个存储引擎

 (图二)

binlog产生于mysql中的server层。

若是mysql采用的为innodb引擎(这里是经典的两阶段提交):

(图三)

binlog文件都有什么?

binlog文件包含两种类型:

  • 索引文件(文件名后缀为.index)用于记录哪些日志文件正在被使用
  • 日志文件(文件名后缀为.00000*)记录数据库所有的DDL和DML(除了数据查询语句)语句事件。

1.索引文件大小:我们可以通过 max_binlog_size  参数设置binlog文件的大小。Binlog最大值,最大和默认值是1GB,该设置并不能严格控制Binlog的大小,尤其是Binlog比较靠近最大值而又遇到一个比较大事务时,为了保证事务的完整性,不可能做切换日志的动作,只能将该事务的所有SQL都记录进当前日志,直到事务结束

2.索引文件删除binlog的删除可以手工删除或自动删除。通过设置 expire_logs_days 实现自动删除

手动删除需登录mysql后执行如下命令:

mysql> reset master;        //删除master的binlog,即手动删除所有的binlog日志
mysql> reset slave; //删除slave的中继日志
mysql> purge master logs before '2019-07-07 17:20:00'; //删除指定日期以前的日志索引中binlog日志文件
mysql> purge master logs to 'binlog.000003'; //删除指定日志文件的日志索引中binlog日志文件

可以通过如下命令确认目前正在使用binlog文件:

-- 通过这句话查询到目前写入的是哪个binlog文件
show master status;

binlog的格式都有什么?

(图四)

binlog一共有三种格式:

  1. statement格式,最后有commit,记录为基本语句
  2. row格式,记录为基于行
  3. MIXED,日志记录使用混合格式
format 定义 优点 缺点
statement 记录的是修改SQL语句 日志文件小,节约IO,提高性能

准确性差,对一些系统函数不能准确复制或不能复制,如now()、uuid()、limit(由于mysql是自选索引,有可能master同salve选择的索引不同,导致更新的内容也不同)等

在某些情况下会导致master-slave中的数据不一致(如sleep()函数, last_insert_id(),以及user-defined functions(udf)等会出现问题)

row 记录的是每行实际数据的变更 准确性强,能准确复制数据的变更 日志文件大,较大的网络IO和磁盘IO
mixed statement和row模式的混合 准确性强,文件大小适中 当binlog format 设置为mixed时,普通复制不会有问题,但是级联复制在特殊情况下会binlog丢失。

在MySQL 5.6中,默认的二进制日志记录格式是 STATEMENT

日志格式也可以在运行时切换。存在两种更改方式:

  1. mysql> SET GLOBAL binlog_format = 'STATEMENT';   基于当前启动的mysql的,若是当前mysql服务重启,则日志格式又恢复为默认。
  2. mysql> SET SESSION binlog_format = 'STATEMENT'; 基于当前请求session的

优先级:session > global > default

我们测试一下日志格式有什么区别:

  首先我们先确认下系统是否开启了binlog ,系统为windows10系统,其中安装的mysql版本是:mysql-5.7.20-winx64

  然后登录mysql 查看binlog是否开启:show variables like 'log_bin';

我们本地安装的mysql的默认的binlog都是关闭的,我们怎么打开它呢?

 找到mysql安装目录下的my.ini文件,然后使用notepad++ 打开(可以使用其他编辑器),(这里注意了,我也使用txt文档打开过,由于txt文档打开的默认格式不是utf-8的,导致txt保存之后存在问题)。

增加如下内容:

# Binary Logging
#MySQL 5.7.3 及以后版本,如果没有设置server-id, 那么设置binlog后无法开启MySQL服务
log-bin=E:/software/tool/environment/mysql/5.7.20/mysql-5.7.20-winx64/logs/binlogs
#binlog日志格式,默认为STATEMENT:每一条SQL语句都会被记录;ROW:仅记录哪条数据被修改并且修改成什么样子,是binlog开启并且能恢复数据的关键;
binlog-format=Row
#binlog过期清理时间;
expire_logs_days=7
#binlog每个日志文件大小;
max_binlog_size=100m
#binlog缓存大小;
binlog_cache_size=4m
#最大binlog缓存大小
max_binlog_cache_size=512m

#Server ID
server-id=201609

然后重启mysql服务

  1. 确认下mysql是否开启show variables like 'log_bin'; 对应的值是on就可以
  2. show variables like 'binlog_format' 看看目前我们的binlog日志是什么,因为我们在my.ini文件中设置了默认的binlog格式,这个时候我们看到的应该是row格式
  3. 执行 
    SET GLOBAL BINLOG_FORMAT = 'STATEMENT';

    把更改后的客户端的连接的 binlog_format都更改为 STATEMENT 格式的

  4. 然后打开一个新的客户端连接,确认下binlog_format是否更改,然后我们后面的操作会在这个连接中进行
  5. 创建一个表 test 
    CREATE TABLE `test` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `num` int(10) DEFAULT '0',
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8

    并插入几条数据

    insert into test value(4,22);
  6. 然后我们查看下现在写入的binlog日志文件是哪个
    -- 然后看一下现在写入的binlog文件
    show master status;

    我这里写入的是binlogs.000003 ,如果是第一次使用的话,写入的应该是binlogs.000001 。

  7. 然后可以跟踪下日志的内容了
    -- 然后看下记录的内容
    show binlog events in 'binlogs.000003';

    我们看这里的info,从begin到commit,中间是真实执行的语句,我们实际上只是执行了insert操作,在这之前,还有use ...操作,这个命令不是我们主动执行的,而是mysql根据当前操作的数据表所在的库,自动添加的

    注意在最后有一个xid event,xid是把binlog和redolog关联起来的关键,binlog和redolog都有一个共同的字段xid,当系统崩溃进行恢复的时候,会按照顺序扫描binlog,若是碰到既有prepare又有commit的redolog,就直接提交;若是碰到只有prepare,而没有commit的redolog,就直接拿xid去binlog查询对应的事务。

    这里简单说下 redo Log,以顺序的方式写入文件,当全部文件写满的时候则回到第一个文件相应的起始位置进行覆盖写(但在做redo checkpoint时,也会更新第一个日志文件的头部checkpoint标记,所以严格来讲也不算顺序写),在InnoDB内部,逻辑上Redo Log被看作一个文件,对应一个space id (InnoDB通过space的概念来组织物理存储,包括不同的表,数据字典,redo,undo等)。
     来自于 https://blog.51cto.com/wangwei007/2287431https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html

  8. 那么我们再把binlog的日志格式更改为 row,看下效果。

    可以看到 这种同 binlog格式为statement相比,前后的begin、commit是相同的, 但是row格式中的binlog没有了sql语句的原文,而是替换成了两个envent,Table_map和Write_rows ,table_map标识的是操作的表名,另外的ROWS_EVENT分为三种:WRITE_ROWS_EVENT,UPDATE_ROWS_EVENT,DELETE_ROWS_EVENT,分别对应insert,update和delete操作。

    我们在这里完全看不出来具体操作内容是什么。我们需要辅助下mysqlbinlog工具。用这个命令解析和查看binlog中的内容。

    我们可以看到这个事务是从459开始。

    在这里我们可以看到server_id 是 201609 以及对应的xid = 182 以及对应的更新的值比如(@1=5,@2=22)最后的xid envent用于表示事务被正确的提交了。里面有一些参数暂未清楚。

  9. 再说下binlog的格式为mixed

    出现的原因:

    1. 由于statement可能会导致主备不一致。

    2. row格式的缺点是比较占用空间,若是使用一个delete删掉10万数据,使用statement就是一个sql语句,但是row格式的话,就要把10万条记录都写到binlog中。这种不仅占用空间还耗费IO资源。  

    所以mysql就采取了个折中方案,也就是有了mixed的格式,mysql自己会判断这条sql语句是否可能引起主备不一致,如果有可能,就用row格式,否则用statement格式。

为什么要写binlog日志?

二进制日志有两个重要目的:

  • 主从复制,对于复制,主复制服务器上的二进制日志提供要发送到从属服务器的数据更改的记录。主服务器将其二进制日志中包含的事件发送到其从属服务器,这些服务器执行这些事件以对主服务器上的数据进行相同的更改。

    MySQL复制功能使用三个线程实现,一个在主服务器上,两个在从服务器上:

    • Binlog转储线程。  主设备创建一个线程,以便在从设备连接时将二进制日志内容发送到从设备。这个线程就是Binlog Dump线程。

      二进制日志转储线程获取主机二进制日志上的锁,用于读取要发送到从机的每个事件。一旦读取了事件,即使在事件发送到从站之前,锁也会被释放。

    • 从属I / O线程。  在从属服务器上发出语句时,从属服务器会创建一个I / O线程,该线程连接到主服务器并要求它发送记录在其二进制日志中的更新。

      从属I / O线程读取主Binlog Dump线程发送的更新 (请参阅上一项)并将它们复制到包含从属中继日志的本地文件。

    • 从属SQL线程。  从属设备创建一个SQL线程来读取由从属I / O线程写入的中继日志,并执行其中包含的事件。

       

  • 某些数据恢复操作需要使用二进制日志。还原备份后,将重新执行备份后记录的二进制日志中的事件。这些事件使数据库从备份点更新。

1.假设执行的是delete语句,row格式下,binlog也会把delete的数据行保存起来,所以当执行完delete之后,发现删错了数据,可以直接把binlog中的delete转为insert,被误删的数据就可以恢复了

2.如果是执行了insert语句,row格式下,binlog也会记录insert的每一个字段,以及精确到刚刚插入的那一行,这个时候直接把insert转为delete,删掉这行数据就可以了

3.如果执行了update语句,row格式下,binlog里面会记录修改前整行数据和修改后的整行数据,恢复update的话,只需要把这个envent前后的两行信息对调一下,再去执行,就可以恢复了。

这里拿一个例子举例:

若是我们线上数据在早晨8点做了全量备份,到了中午12点时,数据库崩溃了(或者删库跑路了),这个时候我们应该怎么做呢?

  1. 首先我们要定位到数据库当时记录的binlog文件
  2. 其次定位到8点到中午十二点的binlog记录
  3. 把数据库的全量备份还原,并把binlog记录导出到sql文件
  4. 执行binlog导出的sql文件,即能够恢复到当时的数据状态。
-- 通过这句话查询到目前写入的是哪个binlog文件
show master status;
-- 查看binlog的日志记录
show binlog events in 'binlogs.000002';
-- 在binlogs目录下 导出update记录
-- mysqlbinlog --start-position=2388 --stop-position=2699 binlogs.000002 > e:\\update2.sql
-- 登录mysql 执行数据恢复
-- source e://update.sql

关于binlog的简单介绍就先说到这里了。加油!

参考文章:

图一:https://dev.mysql.com/doc/refman/5.6/en/binary-log.html

图二:https://zhaodengfeng1989.iteye.com/blog/2419768

图三:https://www.jianshu.com/p/4bcfffb27ed5

https://www.cnblogs.com/rjzheng/p/9721765.html

https://dev.mysql.com/doc/refman/5.6/en/binary-log.html

https://www.cnblogs.com/ivictor/p/5780617.html

https://blog.csdn.net/bohu83/article/details/81568341

https://www.cnblogs.com/lv1572407/p/10499274.html

https://www.cnblogs.com/lixigang/articles/5057113.html

binlog浅析的更多相关文章

  1. InnoDB学习(三)之BinLog

    BinLog又称为二进制日志,是MySQL服务层的数据日志,MySQL所有的存储引擎都支持BinLog.BinLog记录了MySQL中的数据更新和可能导致数据更新的事件,可以用于主从复制或数据恢复.本 ...

  2. 【Mysql学习笔记】浅析mysql的binlog

    最近读一份关于“数据库事务故障恢复"的技术资料,发现对mysql的binlog的认识不够清楚,查阅mysql reference manual有所收获,作为笔记,记录于此. 1. What' ...

  3. db mysql / mysql cluster 5.7.19 / my.cnf / max_binlog_cache_size / binlog

    s mysql修改binlog保存的天数 https://blog.csdn.net/Hu_wen/article/details/80582013 查看binlog过期时间,设置的时间为90天,这个 ...

  4. mysql复制那点事(2)-binlog组提交源码分析和实现

    mysql复制那点事(2)-binlog组提交源码分析和实现 [TOC] 0. 参考文献 序号 文献 1 MySQL 5.7 MTS源码分析 2 MySQL 组提交 3 MySQL Redo/Binl ...

  5. TiKV事务实现浅析

    TiKV事务实现浅析 Percolator事务的理论基础 Percolator的来源 Percolator事务来源于Google在设计更新网页索引的系统时提出的论文Large-scale Increm ...

  6. 源码浅析:MySQL一条insert操作,会写哪些文件?包括UNDO相关的文件吗?

    DML操作的大致流程 在解答上述疑惑之前,我们来梳理一下DML操作的大致流程: 1.语法解析.语义解析 2.生成执行计划 3.事务修改阶段 1) 激活事务,事务状态由not_active变为activ ...

  7. CentOS 7上更改MySQL数据库存储目录浅析

      个人之前总结过两篇文章"MySQL更改数据库数据存储目录"和"Ubuntu上更改MySQL数据库数据存储目录",都是在工作中遇到相关案例后的一个简单总结.当 ...

  8. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  9. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

随机推荐

  1. mysql 存储ipv6

    自定义列 https://groups.google.com/g/sqlalchemy/c/lZw0GipVYFw https://docs.sqlalchemy.org/en/14/core/cus ...

  2. Java学习(十六)

    今天先学了文本标签 <p> <strong>永远不要相信诺克萨斯人的血条!</strong><!--表示一段内容的重要性--> <br /> ...

  3. 关于 RocketMQ 事务消息的正确打开方式 → 你学废了吗

    开心一刻 昨晚和一哥们一起吃夜宵,点了几瓶啤酒 不一会天空下起了小雨,哥们突然道:糟了 我:怎么了 哥们:外面下雨了,我老婆还在等着我去接她 他给了自己一巴掌,说道:真他妈不是个东西 我心想:哥们真是 ...

  4. Linux基础五:网络配置与管理

    五.网络配置与管理 1.网络知识 2.命令 ifconfig命令  <=>  ip  addr  show 命令--查看本地所有网卡配置信息 ens32:本地以太网网卡,lo:本地回环网卡 ...

  5. Qt Creator 源码学习笔记01,初识QTC

    阅读本文大概需要 4 分钟 Qt Creator 是一款开源的轻量级 IDE,整个架构代码全部使用 C++/Qt 开发而成,非常适合用来学习C++和Qt 知识,这也是我们更加深入学习Qt最好的方式,学 ...

  6. 【linux系统】jmeter安装

    安装步骤: 1.下载jmeter安装包  wget https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.4.1.tgz 如报错以下,需使 ...

  7. [bzoj4971]记忆中的背包

    为了使得方案的形式较为单一,不妨强制物品体积为1或$\ge \lceil\frac{w}{2}\rceil$,那么假设最终有$x$个1且$\ge \lceil\frac{w}{2}\rceil$的物品 ...

  8. lilypond 进阶—— 用scheme画图

    lilypond的许多底层设定是通过scheme语言写的,特别是要写函数的时候. 所以了解一下scheme的作用很重要. 不幸的是,不像lilypond本身的代码,scheme代码的结果是不会直接预览 ...

  9. SubsamplingScaleImageView 源码解析

    一开始没打算分析 SubsamplingScaleImageView 这个开源的图片浏览器的,因为这个库在我们 App 中使用了,觉得自己对这个库还是比较熟悉的,结果某天再看看到源码介绍的时候,才发现 ...

  10. 2基因组间鉴定SV

    本文学习费章军老师文章Genome of Solanum pimpinellifolium provides insights into structural variants during toma ...