从mysql2ch到synch,一次重构与升级

项目地址

https://github.com/long2ice/synch

mysql2ch

mysql2ch 从二月份开始到现在已经接近四个月,项目起初是源于公司的需求,同步 MySQL 的数据到 ClickHouse 进行分析与统计。当时调研了一圈,发现并没有符合需求的项目,只找到一个勉强可用的,于是在该项目之上进行开发与完善。

synch

mysql2ch 项目改名为 synch,其主要原因在于 mysql2ch 支持了 postgres 的同步,再取名为 mysql2ch 就有些不合适了,遂改名为 synch,意思是同步到 ClickHouse,其项目目标是同步其它类型的数据库到 ClickHouse 中。

当前架构

synch

设计与实现

最开始的版本非常简陋,只是实现了监听 mysql binlog 然后直接插入到 ClickHouse。在后续的开发与迭代中,逐渐实现了以下功能,以及引入了中间件。

命令行

命令行对于一个独立程序是有必要的。命令行程序可以接受自定义的参数,通过在程序指定不同的参数,可以使用其不同的功能,对于那些需要每次启动都可能会不同的参数,将其放在命令行参数中是有必要的。

配置文件

丰富的配置项可以将程序的自定义配置暴露出来,以满足个性化的运行需求,增强程序的自定义性。

模块分离

该项目分为三个模块,除了源数据库与目标数据库,也就是 ClickHouse 之外,包含生产端、消息队列、消费端。模块的分离是为了解耦,各个模块专注于自身的功能实现以及可靠性。以及借助于消息队列,实现分布式消费。

消息队列

消息队列的引入是为了增加程序的健壮性以及增加生产与消费的性能。通过引入消息队列,将 binlog 先缓冲到消息队列中而不是直接插入到 ClickHouse,避免了当程序崩溃时内存数据的丢失。并且借助于消息队列的 ack 机制,可以保证消息的可靠消费;以及借助消息队列的高吞吐量,将消费者与生产者分离,生产者与消费者之间互不影响,异步工作。

另外一点考虑到 binlog 的有序性,消息队列的选型也是需要考虑的,目前选择了 kafka 和 redis。redis5.0 提供了原生的消息队列并且具有所有消息队列该有的功能,并且消息是有序的,其轻量的特性在并发量不那么大的时候是一个很好的选择;而选择 kafka 是因为其强大的吞吐量,并且单个 topic 的单个分区也是有序的,可以很好的对应需要同步的数据库与数据库表。

redis

redis 的引入其一是为了缓存 MySQL 的 binlog,因为 MySQL 的 binlog 是不断在变化的,当程序崩溃或重启时,需要记录当前的 binlog,然后下次启动时需要从上次的位置继续监听;其二是作为消息队列,相比 kafka 而且因为本身既作为缓存组件也作为消息队列,组件依赖较少。

全量同步

全量同步是基于 ClickHouse 原生的 mysql 函数开发的。由于 ClickHouse 在全量同步的时候对于源数据表的 decimal 类型在 ClickHouse 中会转为 string 类型,于是在此之上做了字段类型的修正。 另外就是早期的方案是先进行全量同步,再进行字段类型的修正,这种方式在数据量大的时候会很耗费时间而且有可能超时,后面做了优化,先进行表结构的同步,然后进行字段类型的修正,最后才进行数据的同步。

增量同步

增量同步的设计也并非是简单的读取数据变动然后直接插入到 ClickHouse 中。由于业务需要支持数据的更新与删除,而 ClickHouse 的删除和更新性能是非常低的,ClickHouse 设计之初也不是为了存储需要频繁变动的数据。于是对于增量同步,选取的方案是将 update 改为 insert+delete 并进行去重等一系列操作,然后根据配置,一般是达到 20000 条或者是每隔 60 秒插入一次,这样就减少了删除操作,虽然也是会牺牲一些实时性。

DDL 支持

在项目的开发中还设计了对 DDL 的支持,当前只支持 MySQL。其实这也并不是那么重要的功能,首先线上的数据库一般很少会执行 DDL 操作,即使执行了 DDL 也可以重新做一次全量同步。并且开启 DDL 同步后在数据量大的时候可能还会引发一些性能问题。

支持 docker

对于 docker 和 docker-compose 的支持可以方便部署,避免直接安装项目的一些依赖问题。

结语

从今年开始逐渐做一些自己的开源项目,也许是感受到了一些乐趣。老实说在做开源项目的过程中还是能学到更多的东西,也可以和更多的人交流,学习。而在此之中得到的成就感,也许是坚持下去的唯一动力,无关利益。