Debezium的MySQL连接器的工作原理

原文参考官网:https://debezium.io/docs/connectors/mysql/#collapse4

       本文将深入Debezium的MySQL连接器(一种kafka connector)的工作细节,包括跟踪表结构(structure of tables)、执行快照任务、把binlog事件转换成记录在Kafka中的Debezium的更改事件、故障发生时连接器的行为。

数据库模式历史(Database schema history)

       当数据库客户端查询数据库的时候,它使用的是数据库当前的模式(schema)。然而,数据库schema随时可能改变,这意味这,MySQL连接器(connector)必须知道在每个insert,update或者delete操作被记录时数据库的schema是什么样的。MySQL连接器不能只使用当前的数据库schema,因为它可能处理的事件是老的事件,在表schema更改前就记录的事件(即不能用新的表schema来处理旧的表schema对应的binlog事件)。幸运的是,MySQL在binlog中包含了数据的行级别改变(row-level change),也包含了对数据库的DDL(包括create、alter、drop等)操作。当MySQL连接器读取binlog的时候,遇到了DDL语句时,连接器会更新内存中的每个表的schema表示(representation of table’s schema),这个schema表示将用于理解后续的每个insert,update,或者delete操作发生时的表结构(structure),从而产生合理的改变事件(change event)。连接器也在一个单独的Kafka topic(即的数据库历史topic)中记录了DDL的语句和DDL语句所在的binlog日志位置。
       当连接器崩溃或者正常停止后再重启时,连接器将从binlog的特定位置(比如特定的时间点)开始读。连接器将通过读取Kafka的数据库历史topic,解析所有的DDL语句,一直到连接器重启时读取binlog的位置,以此重新构建此时的表结构(structure)。
       数据库历史topic只给连接器用的,但是连接器可以选择在另一个kafka topic上生产模式改变事件(schema change events),专门给消费者应用使用。(在数据库模式(schema)历史中,保证事件的全局顺序是很重要的,所以数据库历史topic不能分区,这意味着,创建这个topic的时候必须指定分区数为1。当依赖kafka自动创建topic的机制时,要保证配置选项中的默认分区数num.partitions被设置成1)。

快照(Snapshots)

       在connector的配置中,用snapshot.mode配置项表示快照模式。
       当一个被设置成一个MySQL服务器实例跟从者的MySQL连接器启动的时候,它会默认执行一次数据库初始的一致性快照任务。这是默认的initial模式(mode),因为大多数情况下,MySQL的binlog不再包含数据库的完整历史操作(为了节省磁盘空间,MySQL只会记录一定时间内或者一定大小的binlog)。
MySQL连接器每次获取快照的时候会执行以下的步骤:
1. 获取一个全局读锁,从而阻塞住其他数据库客户端的写操作。
2. 开启一个可重复读语义的事务,来保证后续的在同一个事务内读操作都是在一个一致性快照中完成的。
3. 读取binlog的当前位置。
4. 读取连接器中配置的数据库和表的模式(schema)信息。
5. 释放全局读锁,允许其他的数据库客户端对数据库进行写操作。
6. (可选)把DDL改变事件写入模式改变topic(schema change topic),包括所有的必要的DROPCREATEDDL语句。
7. 扫描所有数据库的表,并且为每一个表产生一个和特定表相关的kafka topic创建事件(即为每一个表创建一个kafka topic)。
8. 提交事务。
9. 记录连接器成功完成快照任务时的连接器偏移量。

       步骤1获取全局读锁的目的在于防止连接器在读取binlog和表schema信息的时候别的数据库客户端进行DDL操作带来的干扰,从步骤1获取锁到步骤5释放锁的时间是很短的,所以对数据库的影响很小。
       如果连接器失败了,或者被再平衡(rebalanced),或者在快照没完成前挂掉了,连接器将在重启的时候开启一个新的快照。一旦连接器完成了初始快照,连接器就会从步骤3中读取的binlog位置开始继续读下去,以确保连接器不再丢失任何更新。如果连接器因为某种原因又挂了,下次重启的时候就会从上次停止的地方接着读。然而,如果连接器停止了很长时间,MySQL可能把老的binlog清理了,连接器上次读取的binlog位置就可能丢失了。在这种情况下,当配置了initial快照模式(默认的mode)的连接器很长时间后重启的时候,MySQL的服务器已经没有连接器要读取的binlog位置,连接器就会报错停止。
       第二种快照模式(snapshot mode)when_needed允许连接器在有必要的任何时候执行快照任务。这个和上面提到的默认的initial快照相似,唯一不同的是:如果连接器重启并且MySQL不再有连接器启动时读取的binlog位置,连接器将执行另一次快照任务而不是失败。这种模式也许是最自动化的,但是在遇到故障时(通常指连接器挂掉很长时间)存在执行额外快照的风险。
       第三种快照模式never,保证了连接器从不执行快照任务。当一个新的连接器配置成这种模式的时候,它会从binlog的起始位置开始读。这不是默认的行为,因为这种模式的连接器(没有快照)要求MySQL的binlog包含连接器所监控的数据库的所有历史,通常MySQL实例不会这么配置,即不会保存所有历史的binlog。特别地,binlog必须包含连接器监控的每个表的至少CREATE TABLE语句。如果这个要求不能满足,连接器将不能合理解释binlog中的行级别事件的结构信息,这样连接器就会简单粗暴地跳过所有丢失表定义的事件。(连接器不能依赖表的当前schema信息,因为表可能会在binlog中记录初始事件后被改变(alter),连接器没办法根据当前的schema合理解释binlog中的事件)
       从Debezium 0.3.4版本开始,第四种快照模式schema_only出现了,它允许连接器启动后从它当前所在MySQL binlog位置开始读。通过schema_only模式,连接器从当前binlog位置开始读,捕获当前表的schema信息,不读取任何数据信息,然后从当前位置开始继续读取binlog。这样导致改变事件流(change event stream)只包括快照开始后发生的改变事件。这种模式对于那些不需要知道数据库完整状态,只想知道连接器启动后的改变的消费者很有用。
       从Debezium 0.7.2开始,第五种快照模式schema_only_recovery,允许一个存在的连接器去恢复中断的或者丢失的数据库历史topic。它和schema_only模式很像,它也不读取任何数据信息,只捕获当前表schema信息。不同的地方在于:

  • 它只可以被用在已经存在的连接器上,作为对连接器配置的更新项。
  • 它从已经存在的连接器上次提交的binlog位置开始读起,而不是binlog的当前位置。

       schema_only_recovery也可以被用于定期清理数据库历史topic(这个topic需要无限期留存kafka日志),如果不定期清理,这个topic的数据可能会不受控制地增长。为了做到定期清理,在把连接器快照模式改成schema_only_recovery模式之前,必须手动删除数据库历史topic。注意,这种模式只有在上次连接器提交偏移量后没有schema变化。否则,在连接器提交的偏移量和schema发生变化的binlog位置之间的binlog事件就会在不一致的schema中被发送出去(已经基于改变后的schema,还没有为之前的事件应用的schema)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章