最近遇到一个服务器磁盘爆满的情况,其原因是过多的 MySQL 开启 binlog 的 ROW 模式后导致binlog 日志过多,占到200G左右。所以关闭了 MySQL 的 binlog 模式。打算了解一下binlog的作用。
1、binlog 的设计目标
binlog 记录了对 MySQL数据库执行更改的所有的写操作,包括所有对数据库的数据、表结构、索引等等变更的操作。
2、binlog 的应用场景
1、主从复制
在 Master 端开启 binlog ,然后将 binlog 发送到各个 Slave 端, Slave 端重放 binlog 来达到主从数据一致。
2、数据恢复
通过使用 mysqlbinlog 工具来恢复数据。
3、binlog 数据格式
1、ROW
基于行的复制(row-based replication, RBR),相当于修改记录,每一行数据的修改都会产生一个数据 。尤其在修改表结构的时候,由于记录的数量相当于表的行数,日志会激增。
优点:准确,不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题;
缺点:日志量太大
2、STATMENT
基于SQL语句的复制( statement-based replication, SBR ),每一条会修改数据的SQL语句会记录到 binlog 中 。即记录update语句,省空间
优点:不需要记录每一行的变化,减少了 binlog 日志量,节约了 IO , 从而提高了性能;
缺点:在某些情况下会导致主从数据不一致,比如执行sysdate() 、 slepp() 等 。
3、MIXED
基于 STATMENT 和 ROW 两种模式的混合复制(mixed-based replication, MBR),一般的复制使用 STATEMENT 模式保存 binlog ,对于一些函数,STATEMENT 模式无法复制的操作使用 ROW 模式保存 binlog。
4、特别注意
ROW格式更加适合用于数据同步与数据恢复上面,易于避免数据不一致的问题;相反,MIXED与STATMENT是基于SQL语句的,不同数据状态下会呈现不一样的效果,最终可能会导致数据不一致的效果。
4、写入策略
对于 InnoDB 存储引擎而言,在进行事务的过程中,首先会把binlog 写入到binlog cache中(因为写入到cache中会比较快,一个事务通常会有多个操作,避免每个操作都直接写磁盘导致性能降低),只有在事务提交时才会记录 binlog ,此时记录还在内存中,那么 binlog 是什么时候刷到磁盘中的呢?
MySQL 其实是通过 sync_binlog 参数控制 binlog 的刷盘时机,取值范围是 0-N:
- 0:每次提交事务binlog不会马上写入到磁盘,而是先写到page cache。不去强制要求,由系统自行判断何时写入磁盘,在Mysql 崩溃的时候会有丢失日志的风险;
- 1:每次提交事务都会执行 fsync 将 binlog 写入到磁盘;
- N:每次提交事务都先写到page cach,只有等到积累了N个事务之后才 fsync 将 binlog 写入到磁盘,在 MySQL 崩溃的时候会有丢失N个事务日志的风险。
所以1为高一致性而0、N 均有日志丢失的风险。
5、情况分析
本次直接开启了ROW格式,而sync_binlog并没有设置。几天内就会记录大量日志于data目录下。而该环境只是非重要的开发环境,且没有主从同步的场景,不需要那么高的可用性,为减少维护成本直接注释 binlog 配置。