摘要: MySQL到ClickHouse数据同步原理及实际

引言

相熟MySQL的敌人应该都晓得,MySQL集群主从间数据同步机制非常欠缺。令人惊喜的是,ClickHouse作为近年来煊赫一时的大数据分析引擎也能够挂载为MySQL的从库,作为MySQL的 "协处理器" 面向OLAP场景提供高效数据分析能力。新近的计划比拟含糊其辞,通过第三方插件将所有MySQL上执行的操作进行转化,而后在ClickHouse端逐个回放达到数据同步。终于在2020年下半年,Yandex 公司在 ClickHouse 社区公布了MaterializeMySQL引擎,反对从MySQL全量及增量实时数据同步。MaterializeMySQL引擎目前反对 MySQL 5.6/5.7/8.0 版本,兼容 Delete/Update 语句,及大部分罕用的 DDL 操作。

根底概念

  • MySQL & ClickHouse

MySQL个别特指残缺的MySQL RDBMS,是开源的关系型数据库管理系统,目前属于Oracle公司。MySQL凭借不断完善的性能以及沉闷的开源社区,吸引了越来越多的企业和个人用户。

ClickHouse是由Yandex公司开源的面向OLAP场景的分布式列式数据库。ClickHouse具备实时查问,残缺的DBMS及高效数据压缩,反对批量更新及高可用。此外,ClickHouse还较好地兼容SQL语法并领有开箱即用等诸多长处。

  • Row Store & Column Store

MySQL存储采纳的是Row Store,表中数据依照 Row 为逻辑存储单元在存储介质中间断存储。这种存储形式适宜随机的增删改查操作,对于按行查问较为敌对。但如果抉择查问的指标只波及一行中少数几个属性,Row 存储形式也不得不将所有行全副遍历再筛选出指标属性,当表属性较多时查问效率通常较低。只管索引以及缓存等优化计划在 OLTP 场景中可能晋升肯定的效率,但在面对海量数据背景的 OLAP 场景就显得有些力不从心了。

ClickHouse 则采纳的是 Column Store,表中数据依照Column为逻辑存储单元在存储介质中间断存储。这种存储形式适宜采纳 SIMD (Single Instruction Multiple Data) 并发解决数据,尤其在表属性较多时查问效率显著晋升。列存形式中物理相邻的数据类型通常雷同,因而人造适宜数据压缩从而达到极致的数据压缩比。

应用办法

  • 部署Master-MySQL

开启BinLog性能:ROW模式
开启GTID模式:解决位点同步时MySQL主从切换问题(BinLog reset导致位点生效)

  • 部署Slave-ClickHouse

获取 ClickHouse/Master 代码编译装置
举荐应用GCC-10.2.0,CMake 3.15,ninja1.9.0及以上

  • 创立Master-MySQL中database及table

  • 创立 Slave-ClickHouse 中 MaterializeMySQL database

此时能够看到ClickHouse中曾经有从MySQL中同步的数据了:

工作原理

  • BinLog Event

MySQL中BinLog Event次要蕴含以下几类:

事务提交后,MySQL 将执行过的 SQL 解决 BinLog Event,并长久化到 BinLog 文件

ClickHouse通过生产BinLog达到数据同步,过程中次要思考3个方面问题:

1、DDL兼容:因为ClickHouse和MySQL的数据类型定义有区别,DDL语句须要做相应转换

2、Delete/Update 反对:引入_version字段,管制版本信息

3、Query 过滤:引入_sign字段,标记数据有效性

  • DDL操作

比照一下MySQL的DDL语句以及在ClickHouse端执行的DDL语句:

能够看到:

1、在DDL转化时默认减少了2个暗藏字段:_sign(-1删除, 1写入) 和 _version(数据版本)
2、默认将表引擎设置为 ReplacingMergeTree,以 _version 作为 column version
3、原DDL主键字段 runoob_id 作为ClickHouse排序键和分区键

此外还有许多DDL解决,比方减少列、索引等,相应代码在Parsers/MySQL 目录下。

  • Delete/Update操作

Update:

能够看到,ClickHouse数据也实时同步了更新操作。

  • Delete:

能够看到,删除id为2的行只是额定插入了_sign == -1的一行记录,并没有真正删掉。

  • 日志回放

MySQL 主从间数据同步时Slave节点将 BinLog Event 转换成相应的SQL语句,Slave 模仿 Master 写入。相似地,传统第三方插件沿用了MySQL主从模式的BinLog生产计划,行将 Event 解析后转换成 ClickHouse 兼容的 SQL 语句,而后在 ClickHouse 上执行(回放),但整个执行链路较长,通常性能损耗较大。不同的是,MaterializeMySQL 引擎提供的外部数据解析以及回写计划隐去了三方插件的简单链路。回放时将 BinLog Event 转换成底层 Block 构造,而后间接写入底层存储引擎,靠近于物理复制。此计划能够类比于将 BinLog Event 间接回放到 InnoDB 的 Page 中。

同步策略

  • 日志回放

v20.9.1版本前是基于位点同步的,ClickHouse每生产完一批 BinLog Event,就会记录 Event 的位点信息到 .metadata 文件:

这样当 ClickHouse 再次启动时,它会把 {‘mysql-bin.000003’, 355005999} 二元组通过协定告知 MySQL Server,MySQL 从这个位点开始发送数据:

存在问题:

如果MySQL Server是一个集群,通过VIP对外服务,MaterializeMySQL创立 database 时 host 指向的是VIP,当集群主从产生切换后,{Binlog File, Binlog Position} 二元组不肯定是精确的,因为BinLog能够做reset操作。

为了解决这个问题,v20.9.1版本后上线了 GTID 同步模式,废除了不平安的位点同步模式。

  • GTID同步

GTID模式为每个 event 调配一个全局惟一ID和序号,间接告知 MySQL 这个 GTID 即可,于是.metadata变为:

其中 0857c24e-4755-11eb-888c-00155dfbdec7 是生成 Event的主机UUID,1-783是曾经同步的event区间

于是流程变为:

源码剖析

  • 概述

在最新源码 (v20.13.1.1) 中,ClickHouse 官网对 DatabaseMaterializeMySQL 引擎的相干源码进行了重构,并适配了 GTID 同步模式。ClickHouse 整个我的项目的入口 main 函数在 /ClickHouse/programs/main.cpp 文件中,主程序会依据接管指令将工作散发到 ClickHouse/programs 目录下的子程序中解决。本次剖析次要关注 Server 端 MaterializeMySQL 引擎的工作流程。

  • 源码目录

与 MaterializeMySQL 相干的次要源码门路:

  • 服务端次要流程

ClickHouse 应用 POCO 网络库解决网络申请,Client连贯的解决逻辑在 ClickHouse/src/Server/*Handler.cpp 的 hander办法里。以TCP为例,除去握手,初始化上下文以及异样解决等相干代码,次要逻辑能够形象成:

  • 数据同步预处理

Client发送的SQL在executeQuery函数解决,次要逻辑简化如下:

次要有三点:

1、解析SQL语句并生成语法树 AST
2、InterpreterFactory 工厂类依据 AST 生成执行器
3、interpreter->execute()

跟进第三点,看看 InterpreterCreateQuery 的 excute() 做了什么:

这里正文很显著,次要执行 CREATE 或 ATTACH DATABASE,持续跟进 createDatabase() 函数:

到这里,相当于将工作分发给DatabaseMaterializeMySQL解决,接着跟踪 loadStoredObjects 函数:

跟进startSynchronization() 绑定的执行函数:

  • 全量同步

MaterializeMySQLSyncThread::prepareSynchronized 负责DDL和全量同步,次要流程简化如下:

ClickHouse作为MySQL从节点,在MaterializeMetadata构造函数中对MySQL端进行了一系列预处理:

1、将关上的表敞开,同时对表加上读锁并启动事务
2、TablesCreateQuery通过SHOW CREATE TABLE 语句获取MySQL端的建表语句
3、获取到建表语句后开释表锁

持续往下走,执行到 metadata.transaction() 函数,该调用传入了匿名函数作为参数,始终跟进该函数会发现最终会执行匿名函数,也就是cleanOutdatedTables以及dumpDataForTables函数,次要看一下 dumpDataForTables 函数:

持续跟踪 tryToExecuteQuery 函数,会调用到 executeQueryImpl() 函数,上文提到过这个函数,但这次咱们的上下文信息变了,生成的执行器发生变化,此时会进行 DDL 转化以及 dump table 等操作:

此时 InterpreterFactory 返回 InterpreterExternalDDLQuery,跟进去看 execute 函数做了什么:

持续跟进去看看 getIdentifierName(arguments[1])).execute() 做了什么事件:

进一步看 InterpreterImpl::getRewrittenQueries 是怎么转化 DDL 的:

实现DDL转换之后就会去执行新的DDL语句,实现建表操作,再回到 dumpDataForTables:

  • 增量同步

还记得startSynchronization() 绑定的执行函数吗?全量同步剖析都是在 prepareSynchronized()进行的,那增量更新呢?

能够看到,while 语句里有一个 binlog_event 的侦听函数,用来侦听 MySQL 端 BinLog 日志变动,一旦 MySQL 端执行相干操作,其 BinLog 日志会更新并触发 binlog_event,增量更新次要在这里进行。

小结

MaterializeMySQL 引擎是 ClickHouse 官网2020年主推的个性,因为该个性在生产环境中属于刚需且目前刚上线不久,整个模块处于高速迭代的状态,因而有许多待欠缺的性能。例如复制过程状态查看以及数据的一致性校验等。感兴趣的话可参考Github上的2021-Roadmap,外面会更新一些社区最近得打算。以上内容如有了解谬误还请斧正。

援用

ClickHouse社区文档

ClickHouse社区源码

MySQL实时复制与实现

MaterializeMySQL引擎剖析

本文分享自华为云社区《MySQL到ClickHouse的高速公路-MaterializeMySQL引擎》,原文作者:FavonianKong 。

点击关注,第一工夫理解华为云陈腐技术~