本文地址:https://www.askmac.cn/archives/mysql-binary-log.html
MySQL Replication(MySQL复制)使用的是一种日志传送复制解决方案。日志传送是指将所有主库(master)上的数据变化存储在一个日志中并发送日志,然后从库(slave)从这些接收到的日志读取信息并依次执行。过程中存储的日志称为二进制日志。由于需要实时地下载日志文件并执行其中内容,因此这意味着一旦一个日志文件事件产生,它会被发送到相连的从库并进行执行。当然,由于网络传输延时和类似问题,它会花上几秒或在甚至最差情况几分钟来接收这些更新。然而,理想状态下这中延时会被控制在1秒内。
为了启用二进制日志,使用 --log-bin
项(在MySQL Server配置文件中进行设置)。
MySQL Server二进制日志默认被建立在 –datadir设置的目录中。其文件名会如以下形式:hostname-bin.000001。你也可以直接将二进制日志文件名和其位置通过 --log-bin
项进行指定。
当启动二进制日志后,日志将以顺序进行建立,而不是仅生成一个大的日志文件。它们将以尾缀序号顺序建立,序号大的代表建立的更晚。二进制日志会在以下三种事件发生后,进行日志切换:
- 当MySQL Server重启时
- 当达到最大日志大小时(max_binlog_size)
- 当SQL命令FLUSH LOGS被执行时
3.8.1 删除日志文件
旧的日志文件默认不会被自动删除。为了删除旧日志文件,你需要设置expire_logs_days或使用SQL命令PURGE BINARY LOGS。
mysql> SET GLOBAL expire_logs_days=1; mysql> PURGE BINARY LOGS BEFORE now() - interval 3 day;
expire_logs_days设置会使得MySQL在进行二进制日志切换时自动删除超过设置天数的旧日志。
而purge binary logs命令实际上有两种格式写法。在这里的例子中显示的是删除从现在计算超出3天的旧日志。第二中语法删除某个日志之前的所有日志。
请注意:当进行旧日志删除时,这些命令是你唯一能使用的。这是因为在删除时需要进行二进制日志索引文件维护,这个文件(binary log index file)会追踪已经现存在的二进制日志。当命令被使用时,索引文件会被自动更行。如果你手工删除二进制日志文件,这些索引文件会由于无法得到相应同步处理而导致主从复制失败。
通常在实现主从复制时,你应该建立起相应的日志保存策略。由于二进制日志需要被用于复制,删除的时候需要特别小心。然而在从库可能主库失去连接后,二进制日志需要保留多久时间才好。如果当一个从库未能连接主库的时候进行了二进制日志删除,当从库重新连接时,它会报错说所需日志文件未能找到。另一个需要考虑的因素是,二进制日志的增长速度。在一个繁忙的业务系统上,二进制日志可能会以每小时1G的速度增长,在这样的系统上,这些日志不可能被保存很多时间,因为它会大量消耗磁盘空间。
不依赖存储引擎
二进制日志是不依赖存储引擎的。这意味着MySQL复制工作和其被使用的存储引擎无关,如MyISAM或InnoDB等。
压缩二进制格式
二进制日志是以压缩二进制格式存储(compact binary format)的。这意味着你不能使用通常的文本工具直接打开来浏览它们。你需要使用mysqlbinlog程序工具来查看二进制日志中的数据,你需要通过命令行来调用此程序:
shell> mysqlbinlog host-bin.000001 host-bin.000002
由于会显示在标准输出上,因此最好使用more或less来帮助浏览:
shell> mysqlbinlog host-bin.000001 | more
mysqlbinlog还有许多其他参数项,如基于时间或文件偏移位置来抽取信息。我们可以通过 --help
项来查看所有选项。
坐标(Coordinate)系统
二进制日志在定位事务上有一套坐标系统。一个二进制日志坐标包含了二进制日志文件名和相关的字节偏移量。例如,hostname-bin.000012,位置342873的组合组成了一个坐标。你可以通过以下命令来获取当前的位置坐标:
mysql> show binary logs;
3.8.2 基于语句的二进制日志
这是MySQL二进制日志记录的传统方式,它在MySQL 3.23被首次引入。由于它包含了实际执行数据更改或潜在数据更改的SQL语句,因此这种日志方式也被称为逻辑日志。这些语句包括有DDL(CREATE, DROP等)和DML(UPDATE,DELETE等…)语句。
使用基于语句的二进制日志的主要优势是它生成的日志比较小。对磁盘空间的使用和复制时候网络带宽需求上都有好处。如,如果更新了1000行数据,仅仅1个单独的update语句被复制执行到从库而已,和1000行数据的传输相比这就小得多了。
它的缺点是对于一致性复制来说具有各种限制,不是所有语句都会被正确传达到远程从库中的。虽然,通常这些限制可以通过其它后继方式进行修补,但是你需要花大量时间来进行维护,使得复制操作顺畅有序。
3.8.3 基于行的二进制日志
从MySQL 5.1开始引入了基于行的二进制日志功能,这种日志方式有助于克服某些基于语句的二进制日志难题。在进行MySQL复制时,通过这种方式替代基于语句的日志,复制操作将发生在行级。因为当主库上的任意一行被改变后,相应的行数据本身会被复制。在基于行的格式加入MySQL后,除了能对很多复杂的复制架构进行支持外,很多相关的新功能也会自动得到支持。
为了改变日志记录模式,你可以使用binlog_format变量,此变量可以在启动时或服务正运行时使用。
SET [GLOBAL|SESSION] BINLOG_FORMAT=[row|statement|mixed|default];
mixed组合模式将使得MySQL对每个独立事件以适当的模式进行记录,这意味着它会使用语句级二进制日志记录,但在需要的时候转换使用行级日志以用户复制。
3.8.4 基于行和基于语句的二进制日志比较
每种二进制日志方法都有它的优缺点,了解它们会对何时使用何种二进制日志模式有更好的理解。
日志文件大小
当使用基于语句的二进制日志时,由于仅针对语句进行日志记录,因此文件大小会很小。而基于行的二进制日志,执行语句中涉及改变的每个行都会被记录下,因此如果行的数量很大,那么所记录的日志也会非常多。此外,基于语句的二进制日志对所有对数据修改的语句进行记录,因此可以作为一种额外的数据审计手段;但是,需要提到的是,基于语句的二进制日志,如果其语句中包含了复杂查询的话,那在从库进行数据更新时,可以会很慢。而基于行的二进制日志则在对于复杂查询数据修改的从库复制上具有优势,速度会更快些。
复制的限制
在基于语句的二进制日志中,并不是所有的语句都可进行复制。而基于行的二进制日志则没有这样的限制。记录更新的结果和记录语句本身之间是不同的,在基于语句的二进制日志,一些语句如不明确结果的用户自定义功能(UDF)或行为(如当使用随机random功能),LOAD_FILE,UUID, USER()和FOUND_ROWS等不会被复制得很好。
主从库MySQL版本
如果主从数据库的MySQL版本不同(或行结构不同),那么基于语句的二进制日志中的复制可能在某些操作中发生明显不同的变化。但是在基于行的二进制日志上,这是不会发生的。
锁
在基于语句的二进制日志中,INSERT … SELECT语句和UPDATE语句会进行表扫描,并迫使其比基于行的二进制日志复制需要更大量的行级锁。基于行的二进制日志在对从库进行INSERT, UPDATE和DELETE语句操作则所需的所更少,不过所需所的级别更高些;然而,由于基于行的二进制日志会复制每行被修改的行,因此二进制日志会被锁定更长时间来记录数据信息,这会导致并行性能问题。
时间点恢复(Point-in-Time Recovery)
基于语句的二进制日志不仅对于管理员来说方面阅读和审计,而且可用于恢复奔溃了的数据库(或一些其他不好的状况),将数据库回到某个时间点上。基于行的二进制值日志则并不是以一种可读的方式进行的记录,此外,基于行的二进制日志,你无法得知从库(slave)从主库(master)上得到了什么语句并进行了执行。这是基于语句的二进制日志的一种优势。
Comment