数据库
首页 > 数据库> > HTAP | MySQL 到 ClickHouse 的高速公路

HTAP | MySQL 到 ClickHouse 的高速公路

作者:互联网

作者:TCeason 青云科技数据库研发工程师

2000 年至今,MySQL[1] 一直是全球最受欢迎的 OLTP(联机事务处理)数据库,ClickHouse[2] 则是近年来受到高度关注的 OLAP(联机分析处理)数据库。那么二者之间是否会碰撞出什么火花呢?

本文将带领大家 打破异构数据库壁垒,将 MySQL 数据同步至 ClickHouse。

背景

1、MySQL 复制的发展历程

图 1-1 MySQL 复制的发展历程

图 1-1 详细罗列了 MySQL 复制的发展历程。

2001 年的 MySQL 3.23 版本就已经支持了同构数据库 异步复制;由于是异步复制,根本无法在实际生产中大批量使用。

2013 年 MySQL 5.7.2 版本支持 增强半同步复制 能力,才勉强算得上是企业级可用的数据同步方案。

2016 年 MySQL 5.7.17 支持了 MGR,并不断地发展成熟,变成了一个金融级别可用的数据同步方案。

而对于同构的 MySQL 数据同步,接下来要做的就是不断地优化体验,提升同步时效性,解决网络异常下的各类问题。

基于此,各大厂商也开始做自己的高可用同步组件。例如由 QingCloud 数据库研发团队研发并开源的 Xenon,就具备了真正的强一致性和高可用能力。

2、MySQL + Xenon

图 1-2 中的 Xenon 是由类 Raft 算法来实现的高可用组件,用来管理 MySQL 选举和探活,并订正数据准确性。MySQL 数据同步则依然使用 Semi-Sync Replication 或者 MGR,从而达到数据强一致性、无中心化自动选主且主从秒级切换,以及依托于云的跨区容灾能力。

ClickHouse 同步 MySQL 数据

为了加速 OLAP 查询,QingCloud MySQL Plus[3](MySQL + Xenon) 借用 ClickHouse 来同步 MySQL 数据。

1、ClickHouse 概述

ClickHouse 是一个用于联机分析 (OLAP) 的列式数据库管理系统 (DBMS)。ClickHouse 构思于 2008 年,最初是为 YandexMetrica(世界第二大Web分析平台)而开发的。多年来一直作为该系统的核心组件被该系统持续使用着,并于 2016 年宣布开源。

从目前最新的 DB-Engines 中可以看到其排名曲线一路高涨,并且各大厂在重要业务上已经大量部署,这是一个很明显的趋势。因此,我们似乎可以认定 ClickHouse 的火热并不只是一时现象,它将长久地存活下去。而且,ClickHouse 灵活的外部表引擎,可轻松实现与 MySQL 的数据同步,接下来让我们了解一下。

2、MySQL Table Engine

MySQL Table Engine 的特性。

ClickHouse 最开始支持表级别同步 MySQL 数据,通过外部表引擎 MySQL Table Engine 来实现同 MySQL 表的映射。从 information_schema 表中获取对应表的结构,将其转换为 ClickHouse 支持的数据结构,此时在 ClickHouse 端,表结构建立成功。但是此时,并没有真正去同步数据。只有向 ClickHouse 中的该表发起请求时,才会主动的拉取要同步的 MySQL 表的数据。

MySQL Table Engine 使用起来非常简陋,但它是非常有意义的。因为这是第一次打通 ClickHouse 和 MySQL 的数据通道。但是,缺点异常明显:

i. 仅仅是对 MySQL 表关系的映射;

ii. 查询时传输 MySQL 数据到 ClickHouse,会给 MySQL 可能造成未知的网络压力和读压力,可能影响 MySQL 在生产中正常使用。

基于 MySQL Table Engine 只能映射 MySQL 表关系的缺点,QingCloud ClickHouse 团队实现了 MySQL Database Engine。

3、MySQL Database Engine

MySQL Database Engine 的特性。

MySQL Database Engine 是库级别的映射,要从 information_schema 中拉取待同步库中包含的所有 MySQL 表的结构,解决了需要建立多表的问题。但仍然还有和 MySQL Table Engine 一样的缺点:查询时传输 MySQL 数据到 ClickHouse,给 MySQL 可能造成未知的网络压力和读压力,可能影响 MySQL 在生产中正常使用。

4、借用第三方软件同步

除去上面提到的 MySQL Table Engine 、MySQL Database Engine 两种方式,还有可以采用第三方软件来同步数据,比如 Canal 或者 Kafka,通过解析 MySQL binlog,然后编写程序控制向 ClickHouse 写入。这样做有很大的优势,即同步流程自主可控。但是也带来了额外的问题:

i. 增加了数据同步的复杂度。

ii. 增加了第三方软件,使得运维难度指数级增加。

基于此,我们又可以思考一个问题,ClickHouse 能否主动同步并订阅 MySQL 数据呢?

Materialize MySQL

为了解决 MySQL Database Engine 依然存留的问题,支持 ClickHouse 主动同步并订阅 MySQL 数据,QingCloud ClickHouse 团队自主研发了 MaterializeMySQL[4] 引擎。

1、简述 MaterializeMySQL

MaterializeMySQL 引擎是由 QingCloud ClickHouse 团队自主研发的库引擎,目前作为实验特性合并到 ClickHouse 20.8 版本中,是对 MySQL 库级别关系的映射,通过消费 binlog 存储到 MergeTree 的方式来订阅 MySQL 数据。

具体使用方式就是一条简单的 CREATE DATABASE SQL 示例:

CREATE DATABASE test ENGINE = MaterializeMySQL(
  '172.17.0.3:3306', 'demo', 'root', '123'
)

# 172.17.0.3:3306 - MySQL 地址和端口
# demo - MySQL 库的名称
# root - MySQL 同步账户
# 123 - MySQL 同步账户的密码

2、MaterializeMySQL 的设计思路

MaterializeMySQL 的设计思路如下:

  1. 首先检验源端 MySQL 参数是否符合规范;
  2. 再将数据根据 GTID 分割为历史数据和增量数据;
  3. 同步历史数据至 GTID 点;
  4. 持续消费增量数据。

3、MaterializeMySQL 的函数流程

如图 3-1 所示,MaterializeMySQL 函数的主体流程为:

CheckMySQLVars -> prepareSynchronized -> Synchronized

(1)CheckMySQLVars

检验参数比较简单,就是要查询这些参数是否符合预期。

SHOW VARIABLES WHERE (Variable_name = 'log_bin'
AND upper(Value) = 'ON')
OR (Variable_name = 'binlog_format'
AND upper(Value) = 'ROW')
OR (Variable_name = 'binlog_row_image'
AND upper(Value) = 'FULL')
OR (Variable_name = 'default_authentication_plugin'
AND upper(Value) = 'MYSQL_NATIVE_PASSWORD')
OR (Variable_name = 'log_bin_use_v1_row_events'
AND upper(Value) = 'OFF');

(2)prepareSynchronized

这一步来实现历史数据的拉取。

std::optional<MaterializeMetadata> MaterializeMySQLSyncThread::prepareSynchronized()
{
    connection = pool.get();
    MaterializeMetadata metadata(
connection, DatabaseCatalog::instance().getDatabase(database_name)->getMetadataPath() + "/.metadata", mysql_database_name, opened_transaction);
    if (!metadata.need_dumping_tables.empty())
    {
        Position position;
        position.update(metadata.binlog_position, metadata.binlog_file, metadata.executed_gtid_set);
        metadata.transaction(position, [&]()
        {
            cleanOutdatedTables(database_name, global_context);
            dumpDataForTables(connection, metadata, query_prefix, database_name, mysql_database_name, global_context, [this] { return isCancelled(); });
         });
    }
    connection->query("COMMIT").execute();
}

在 MySQL 中,demo 库下有一个表 t ,主键为 ID , 普通列 col_1。

CREATE TABLE demo.t (
  id int(11) NOT NULL,
  col_1 varchar(20) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE = InnoDB;

在 ClickHouse 中,依然是id 作为主键列,但是,多了隐藏列 _sign 和 _version。

i. _sign:值只有 1 和 -1。其中,1 代表这行数据存在,-1 代表这行数据被删除。

ii. _version:只会读到 version 高的值,会在后台不断合并主键相同的行,最终保留 Version 最高的行。

CREATE TABLE test.t
(
    `id` Int32,
    `col_1` Nullable(String),
    `_sign` Int8 MATERIALIZED 1,
    `_version` UInt64 MATERIALIZED 1
)
ENGINE = ReplacingMergeTree(_version)
PARTITION BY intDiv(id, 4294967)
ORDER BY tuple(id)

(3)Synchronized

在 prepareSynchronized 中,我们得到了历史数据以及历史数据位点信息,并且获得了与 MySQL 的 Binlog 传输通道。接下来就是从该位点同步增量数据。通过 readOneBinlogEvent 函数读取每一条 binlog 内容,然后使用 onEvent 转换成 ClickHouse 的语句格式即可。最终为了数据安全性,调用 flushBuffersData 函数将数据落盘。

client.connect();
client.startBinlogDumpGTID(randomNumber(), mysql_database_name, metadata.executed_gtid_set, metadata.binlog_checksum);
Buffers buffers(database_name);
while (!isCancelled())
{
    BinlogEventPtr binlog_event = client.readOneBinlogEvent(std::max(UInt64(1), max_flush_time - watch.elapsedMilliseconds()));
    if (binlog_event)
        onEvent(buffers, binlog_event, *metadata);
    if (!buffers.data.empty())
        flushBuffersData(buffers, *metadata);
}

HTAP 应用场景

当我们打通了 ClickHouse 和 MySQL 的复制通道,而 ClickHouse 的分析能力又是如此让人惊喜,那么我们是不是可以用 MySQL + ClickHouse 实现 HTAP 呢?

在图 4-1 中的架构,依然使用高可用组件 Xenon 来管理 MySQL 复制,同时 Xenon 增加了对 ClickHouse 的监管,通过 MaterializeMySQL 来同步 MySQL 数据。

在之前的架构图中,使用 MySQL 只读实例来进行商务分析、用户画像等分析业务。而现在可以直接将 ClickHouse 作为一个分析实例加入到 MySQL 复制中,替代一部分只读实例进行分析计算。同时 ClickHouse 本身支持了海量函数来支持分析能力的同时还支持标准 SQL,相信可以让使用者享受到很好的体验。

目前的 ClickHouse 可以支持同步 MySQL 5.7 和 8.0 的数据,不支持同步 MySQL 5.6 的数据。不过,作为一个实验特性, MaterializeMySQL 的时间线相当于是 2001 年刚刚支持复制的 MySQL。欢迎大家一起来贡献和维护 MaterializeMySQL。

[1]. MySQL : https://www.mysql.com/

[2]. ClickHouse : https://clickhouse.tech/docs/en/

[3]. MySQL Plus:https://www.qingcloud.com/products/mysql-plus/

[4]. MaterializeMySQL:https://clickhouse.tech/docs/en/engines/database-engines/materialize-mysql/

关于 RadonDB

RadonDB 开源社区是一个面向云原生、容器化的数据库开源社区, 为数据库技术爱好者提供围绕主流开源数据库(MySQL、PostgreSQL、Redis、MongoDB、ClickHouse 等)的技术分享平台,并提供企业级 RadonDB 开源产品及服务。

目前 RadonDB 开源数据库系列产品已被 光大银行、浦发硅谷银行、哈密银行、泰康保险、太平保险、安盛保险、阳光保险、百年人寿、安吉物流、安畅物流、蓝月亮、天财商龙、罗克佳华、升哲科技、无锡汇跑体育、北京电信、江苏交通控股、四川航空、昆明航空、国控生物 等上千家企业及社区用户采用。

RadonDB 可基于云平台与 Kubernetes 容器平台交付,不仅提供覆盖多场景的数据库产品解决方案,而且提供专业的集群管理和自动化运维能力,主要功能特性包括:高可用主从切换、数据强一致性、读写分离、一键安装部署、多维指标监控&告警、弹性扩容&缩容、横向自由扩展、自动备份&恢复、同城多活、异地灾备 等。RadonDB 仅需企业及社区用户专注于业务层逻辑开发,无需关注集群高可用选型、管理和运维等复杂问题,帮助企业及社区用户大幅度提升业务开发与价值创新的效率!

GitHub:

https://github.com/radondb

本文将介绍 MaterializeMySQL 引擎是如何实现 MySQL 数据同步至 ClickHouse 的。

标签:Engine,同步,MaterializeMySQL,MySQL,HTAP,数据,ClickHouse
来源: https://www.cnblogs.com/radondb/p/14866306.html