介绍 Binary Log
Binary Log 被称为二进制日志, Binary Log 主要记录数据库的更新事件,比如创建数据表、更新表中的数据等信息。Binary Log 是在 MySQL 的执行器层(server 层)实现的,与存储引擎无关,因此只要开启使用 Binary Log,执行器就会把对数据库的更新事件记录到 Binary Log。
Binary Log 的作用 / 功能:
- 数据恢复:反向解析 binlog 文件,并执行反向 SQL,恢复数据
- 数据复制:在存储高可用架构中,用 Binary Log 把数据从一个服务器复制到另一个服务器,完成服务器间的数据同步
操作 Binary Log
20 | 日志(下):系统故障,如何恢复数据?
操作 Binary Log,主要包括查看 Binary Log、刷新 Binary Log,用 Binary Log 恢复数据,以及删除 Binary Log。查看 Binary Log
查看当前正在写入的 Binary Log:show master status;
查看所有的 Binary Log:show binary logs;
查看指定 Binary Log 文件中所有的数据更新事件:show binlog events in '文件名';
刷新 Binary Log
刷新 Binary Log:flush binary logs;
刷新 Binary Log 的意思是,关闭服务器正在写入的 Binary Log 文件,重新打开一个新的 Binary Log 文件,文件名的后缀在现有的基础上 + 1。使用 mysqlbinlog 恢复数据
这条命令的意思是:执行 Binary Log 文件中从位置 xxx 开始,到 yyy 截止的所有数据更新操作。mysqlbinlog –start-positon=xxx --stop-position=yyy '二进制文件名' | mysql -u 用户 -p
这里的截止位置也可以不写,意思是从位置 xxx 开始,执行 Binary Log 文件中的所有数据更新操作。
数据恢复:mysqlbinlog删除所有的 Binary Log 文件
删除所有的 Binary Log 文件:reset master;
该命令的执行结果:所有 Binary Log 文件都被删除了,MySQL 从头准备了一个“.000001”为后缀的新的 Binary Log 文件。
我们也可以通过以下的命令,删除比指定 Binary Log 文件编号小的所有 Binary Log 文件:purge master logs to '文件名';
Binary Log 的参数配置
binlog_cache_size:每个线程的 binlog cache 的内存大小(默认值是 32 KB)
sync_binlog:Binary Log 的写入策略(默认值是 1)
binlog_format:Binary Log 的格式(默认值是 row)
binlog_expire_logs_seconds:Binary Log 的过期时间(默认值是 30 天)
binlog_expire_logs_seconds 设置之后不会立即清除过期的 Binary Log,清除的触发条件是:
- binlog大小超过max_binlog_size
- 手动执行 flush logs
- 重新启动时(MySQL将会创建一个新的 Binary Log 文件)
Binary Log 的写入策略
23 | MySQL是怎么保证数据不丢的?
Binary Log 的写入策略是:
- 事务执行的过程中,执行器先把 Binary Log 写入内存(binlog cache);
- 事务提交的时候,执行器再把 binlog cache 里事务的完整 Binary Log 写入 Binary Log 文件中,并清空 binlog cache。
一个事务的 Binary Log 是不能被拆开的,因此无论这个事务多大,都要确保一次性写入磁盘。 这就涉及到了 binlog cache 的保存问题。 系统给 binlog cache 分配了一片连续的内存,每个线程一个 binlog cache,参数 binlog_cache_size 用来控制一个线程的 binlog cache 所占内存的大小。 如果 binlog cache 所占内存的大小超过了这个参数规定的值, binlog cache 中的内容就要暂存到磁盘的临时文件。事务提交的时候,再从磁盘读取,把事务的完整 Binary Log 写到 Binary Log 文件。
从上图中可以看到,每个线程有自己 binlog cache,但是共用同一份 Binary Log 文件,binlog cache 里的数据持久化到磁盘需要经过 write 和 fsync 两个过程 。
- write 是指:把 binlog cache 里的 Binary Log 写入文件系统的页缓存(Page Cache)。并没有把数据持久化到磁盘,所以速度比较快。
- fsync 是指:将数据持久化到磁盘的操作。一般情况下,我们认为 fsync 才占磁盘的 IOPS。
write 和 fsync 的时机,是由参数 sync_binlog 控制的:
- sync_binlog=0:表示每次提交事务时,只是执行 write,而不执行 fsync;
- sync_binlog=1:表示每次提交事务时,执行 fsync 后才返回(参数的默认值);
- sync_binlog=N(N>1):表示每次提交事务时,执行 write,但累积 N 个事务后才执行 fsync。
因此,在出现 IO 瓶颈的场景里,将 sync_binlog 设置成一个比较大的值,可以提升性能。
在实际的业务场景中,考虑到丢失日志量的可控性,一般不建议将 sync_binlog 参数设成 0,比较常见的是将其设置为 100~1000 中的某个数值。但是,将 sync_binlog 设置为 N,对应的风险是:如果主机发生异常重启,会丢失最近 N 个事务的 Binary Log。
通常我们说 MySQL 的“双 1”配置,指的就是 sync_binlog 和 innodb_flush_log_at_trx_commit 都设置成 1。也就是说,一个事务提交前,需要等待两次刷盘,一次是 Redo Log 刷盘(prepare 阶段),一次是 Binary Log 刷盘。
Binary Log 的格式
24 | MySQL是怎么保证主备一致的?
Binary Log 有三种格式,一种是 statement,一种是 row。还有一种叫作 mixed,其实 mixed 就是前两种格式的混合。使用哪种格式由参数 binlog_format 控制,默认值是 row。
- statement 格式的 Binary Log 记录的是:SQL 语句
- row 格式的 Binary Log 记录的是:事务的执行所必要的信息,能够保证使用 Binary Log 恢复数据的时候,执行结果和原库相同。
- insert 语句的 Binary Log 里会记录:所有的字段信息
- update 语句的 Binary Log 里会记录:修改前整行的数据和修改后整行的数据
- delete 语句的 Binary Log 里会记录:被删掉的行的整行信息
基于上面的信息,我们来讨论一个问题:为什么会有 mixed 这种 Binary Log 格式的存在场景?
推论过程是这样的:
- 因为有些 statement 格式的 Binary Log 可能会导致主备不一致,所以要使用 row 格式。
- 但 row 格式的缺点是,很占空间。比如你用一个 delete 语句删掉 10 万行数据,用 statement 的话就是一个 SQL 语句被记录到 Binary Log 中,占用几十个字节的空间。但如果用 row 格式的 Binary Log,就要把这 10 万条记录都写到 Binary Log 中。这样做,不仅会占用更大的空间,同时写 Binary Log 也要耗费 IO 资源,影响执行速度。
- 所以,MySQL 就取了个折中方案,也就是有了 mixed 格式的 Binary Log 。mixed 格式的意思是,MySQL 自己会判断这条 SQL 语句是否可能引起主备不一致,如果有可能,就用 row 格式,否则就用 statement 格式。
也就是说,mixed 格式可以利用 statment 格式的优点(节省存储空间),同时又避免了数据不一致的风险(statment 格式的缺点)。