引入
Mysql 5.0以后,支持通过binary log(二进制日志)以支持主从复制。复制允许将来自一个MySQL数据库服务器(master) 的数据复制到一个或多个其他MySQL数据库服务器(slave),以实现灾难恢复、水平扩展、统计分析、远程数据分发等功能。
下面以mysql主从复制为例,讲解一个从库是如何从主库拉取binlog,并回放其中的event的完整流程。mysql主从复制的流程如下图所示:
主要分为3个步骤:
- master在每次准备提交事务完成数据更新前,将改变记录到二进制日志(binary log)中
- slave启动一个I/O线程来读取主库上binary log中的事件,并记录到slave自己的中继日志(relay log)中。
- slave还会起动一个SQL线程,该线程从relay log中读取事件并在备库执行,从而实现备库数据的更新。
这是Binlog的工作原理,基于此,我们可以拓展出它的一些应用场景。
Binlog应用场景
读写分离
最典型的场景就是通过Mysql主从之间通过binlog复制来实现横向扩展,来实现读写分离。如下图所示:
在这种场景下:
- 有一个主库Master,所有的更新操作都在master上进行
- 同时会有多个Slave,每个Slave都连接到Master上(拿数据时在slave之间做负载均衡),获取binlog在本地回放,实现数据复制。
数据恢复
如何将脏数据恢复成原来的样子?如果恢复已经被删除的记录?这些都可以通过反解binlog来完成。
关于这一点的详细介绍会放到之后对于Binlog的数据处理上来做讨论。
保证数据最终一致性
在实际开发中,我们经常会遇到一些需求,在数据库操作成功后,需要进行一些其他操作,如:发送一条消息到MQ中、更新缓存或者更新搜索引擎中的索引等。
以数据库与redis缓存的一致性为例:操作数据库成功了,可能会更新redis失败;反之亦然。很难保证二者的完全一致。具体案例可以参考:缓存与数据库一致性问题。
如果数据库操作成功,必然会产生binlog。之后,我们通过一个组件,来模拟的mysql的slave,拉取并解析binlog中的信息。通过解析binlog的信息,去异步的更新缓存、索引或者发送MQ消息,保证数据库与其他组件中数据的最终一致。在这里,我们将模拟slave的组件,统一称之为binlog同步组件。
当我们通过binlog同步组件完成数据一致性时,此时架构可能如下图所示:
我们可以进行一些优化,之所以不同场景模拟多个slave来连接master获取同一份binlog,本质上要满足的是:一份binlog数据,同时提供给多个不同业务场景使用,彼此之间互不影响。因此,我们完全可以将binlog,统一都发送到MQ中,不同的应用场景使用不同的consumer group来消费,彼此之间互不影响。此时架构如下图所示:
当将binlog发送到MQ中后,我们就可以利用MQ的一些高级特性了。例如binlog发送到MQ过快,消费方来不及消费,可以利用MQ的消息堆积能力进行流量削峰。还可以利用MQ的消息回溯功能,例如一个业务需要消费历史的binlog,此时MQ中如果还有保存,那么就可以直接进行回溯。
异地多活
一个更大的应用场景,异地多活场景下,跨数据中心之间的数据同步。这种场景的下,多个数据中心都需要写入数据,并且往对方同步。以下是一个简化的示意图:
这里有一些特殊的问题需要处理。典型的包括:
- 数据冲突:双方同时插入了一个相同主键的值,那么往对方同步时,就会出现主键冲突的错误。
- 数据回环:一个库A中插入的数据,通过binlog同步到另外一个库B中,依然会产生binlog。此时库B的数据再次同步回库A,如此反复,就形成了一个死循环。
关于这一点在之后的文章中会介绍。