不会吧,不会吧,还有人不知道 binlog ?
时间:2021-09-07 11:27:34
手机看文章
扫描二维码
随时随地手机看文章
[导读]本文读完需7分钟,速读仅需4分钟。前言上篇阿星详细聊了redolog(重做日志),但是在MySQL数据库中还有一种二进制日志叫binlog(归档日志)。redolog它是物理日志,记录内容是“在某个数据页上做了什么修改”,属于InnoDB存储引擎。而binlog是逻辑日志,记录内...
本文读完需7分钟,速读仅需4分钟。
前言
上篇阿星详细聊了redo log
(重做日志),但是在MySQL
数据库中还有一种二进制日志叫binlog
(归档日志)。redo log
它是物理日志,记录内容是“在某个数据页上做了什么修改”,属于InnoDB
存储引擎。而binlog
是逻辑日志,记录内容是语句的原始逻辑,类似于“给ID=2这一行的c字段加1”,属于MySQL Server
层。binlog
不管用什么存储引擎,只要发生了表数据更新,都会产生binlog
日志。那binlog
到底是用来干嘛的?可以说MySQL
数据库的数据备份、主备、主主、主从都离不开binlog
,需要依靠binlog
来同步数据,保证数据一致性。binlog
会记录所有涉及更新数据的逻辑操作,并且是顺序写。记录格式
binlog
日志有三种格式,可以通过binlog_format
参数指定。- statement
- row
- mixed
statement
,记录的内容是SQL
语句原文,比如执行一条update T set update_time=now() where id=1
,记录的内容如下。同步数据时,会执行记录的SQL
语句,但是有个问题,update_time=now()
这里会获取当前系统时间,直接执行会导致与原库的数据不一致。为了解决这种问题,我们需要指定为row
,记录的内容不再是简单的SQL
语句了,还包含操作的具体数据,记录内容如下。row
格式记录的内容看不到详细信息,要通过mysqlbinlog
工具解析出来。update_time=now()
变成了具体的时间update_time=1627112756247
,条件后面的@1、@2、@3都是该行数据第1个~3个字段的原始值(假设这张表只有3个字段)。这样就能保证同步数据的一致性,通常情况下都是指定为row
,这样可以为数据库的恢复与同步带来更好的可靠性。但是这种格式,需要更大的容量来记录,比较占用空间,恢复与同步时会更消耗IO
资源,影响执行速度。所以就有了一种折中的方案,指定为mixed
,记录的内容是前两者的混合。MySQL
会判断这条SQL
语句是否可能引起数据不一致,如果是,就用row
格式,否则就用statement
格式。写入机制
binlog
的写入时机也非常简单,事务执行过程中,先把日志写到binlog cache
,事务提交的时候,再把binlog cache
写到binlog
文件中。因为一个事务的binlog
不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache
。我们可以通过binlog_cache_size
参数控制单个线程binlog cache
大小,如果存储内容超过了这个参数,就要暂存到磁盘(Swap
)。binlog
日志刷盘流程如下- 上图的write,是指把日志写入到文件系统的page cache,并没有把数据持久化到磁盘,所以速度比较快
- 上图的fsync,才是将数据持久化到磁盘的操作
write
和fsync
的时机,可以由参数sync_binlog
控制,默认是0
。为0
的时候,表示每次提交事务都只write
,由系统自行判断什么时候执行fsync
。虽然性能得到提升,但是机器宕机,page cache
里面的binglog
会丢失。为了安全起见,可以设置为1
,表示每次提交事务都会执行fsync
,就如同binlog日志刷盘流程一样。最后还有一种折中方式,可以设置为N(N>1)
,表示每次提交事务都write
,但累积N
个事务后才fsync
。在出现IO
瓶颈的场景里,将sync_binlog
设置成一个比较大的值,可以提升性能。同样的,如果机器宕机,会丢失最近N
个事务的binlog
日志。站在巨人的肩膀上- 《MySQL实战45讲》
- 《从零开始带你成为MySQL实战优化高手》
- 《MySQL技术Innodb存储引擎》