当前位置: 首页 > 科技观察

不行不行,还有不知道Binlog的吗?

时间:2023-03-13 05:00:30 科技观察

本文转载自微信公众号“程序猿之星”,作者程序猿阿星。转载本文,请联系程序员阿星公众号。在前言中,阿星详细的讲了重做日志(redolog),但是在MySQL数据库中还有一种叫做binlog(archivelog)的二进制日志。Redolog是物理日志,记录内容是“对某个数据页做了什么修改”,属于InnoDB存储引擎。binlog是逻辑日志,记录的内容是语句的原始逻辑,类似于“ID=2行的c字段加1”,属于MySQLServer层。不管binlog使用什么存储引擎,只要表数据有更新,都会产生binlog日志。那么binlog是用来做什么的呢?可以说MySQL数据库的数据备份、主备、主从、主从都离不开binlog。需要依赖binlog来同步数据,保证数据的一致性。Binlog会记录所有涉及更新数据的逻辑操作,并且是顺序写入的。记录格式binlog日志有三种格式,可以通过binlog_format参数指定。statementrowmixed指定语句,记录的内容为SQL语句的原文。例如执行updateTsetupdate_time=now()whereid=1,记录的内容如下。同步数据时,会执行记录的sql语句,但是有个问题,这里的update_time=now()会获取到当前系统时间,直接执行会导致数据与原数据库不一致。为了解决这个问题,我们需要指定行。记录的内容不再是简单的SQL语句,还包含了操作的具体数据。记录内容如下。row格式记录的内容无法详细查看,必须通过mysqlbinlog工具解析。update_time=now()变成具体时间update_time=1627112756247,条件后面的@1、@2、@3是行数据第一到第三字段的原始值(假设这张表只有3个字段)。这样可以保证同步数据的一致性,通常指定为行,可以为数据库的恢复和同步带来更好的可靠性。但是这种格式需要较大的记录容量,占用空间较大,恢复和同步时会消耗较多的IO资源,影响执行速度。于是就有了一个折中方案,指定为mixed,录制的内容是前两者的混合。MySQL会判断这条SQL语句是否会导致数据不一致,如果是则使用行格式,否则使用语句格式。写机制binlog的写时序也很简单。事务执行过程中,首先将日志写入binlog缓存,当事务提交时,将binlog缓存写入binlog文件。因为一个事务的binlog是不可拆解的,所以无论事务有多大,都必须写入一次。因此,系统会为每个线程分配一块内存作为binlog缓存。我们可以通过binlog_cache_size参数来控制单个线程的binlog缓存大小。如果存储内容超过这个参数,则必须暂时存储到磁盘(Swap)。binlog日志刷写过程如下:上图中的write指的是将日志写入文件系统的pagecache,并没有将数据持久化到磁盘,所以速度比较快。上图中的fsync是将数据持久化到磁盘操作write和fsync的时机可以通过参数sync_binlog来控制,默认为0,为0时表示每次提交一个事务,只写,系统判断什么时候执行fsync。虽然性能提升了,但是机器宕机了,pagecache中的binglog会丢失。为了安全,可以设置为1,表示每次提交事务都会执行fsync,就像binlog日志的flushing过程一样。最后还有一个折中的方法,可以设置为N(N>1),也就是说每提交一个事务,都会写入,但是累积N个事务后才会fsynced。在出现IO瓶颈的场景下,将sync_binlog设置为一个比较大的值可以提升性能。同样,如果机器宕机,最后N笔交易的binlog日志也会丢失。