首页 > 数据库 >从 MySQL 到 ClickHouse 实时复制与实现

从 MySQL 到 ClickHouse 实时复制与实现

时间:2022-12-14 18:00:25浏览次数:45  
标签:MySQL 实时 t1 version mysql sign ClickHouse

ClickHouse 可以挂载为 MySQL 的一个从库 ,先全量再增量的实时同步 MySQL 数据,这个功能可以说是今年最亮眼、最刚需的功能,基于它我们可以轻松的打造一套企业级解决方案,让 OLTP 和 OLAP 的融合从此不再头疼。

目前支持 MySQL 5.6/5.7/8.0 版本,兼容 Delete/Update 语句,及大部分常用的 DDL 操作。

代码还处于 Alpha 版本阶段,毕竟是两个异构生态的融合,仍然有不少的工作要做,同时也期待着社区用户的反馈,以加速迭代。

代码获取

由于还在验收阶段,我们只好把 github 上的 pull request 代码 pull 到本地。​

git fetch origin pull/10851/head:mysql_replica_experiment

开始编译…

MySQL Master

我们需要一个开启 binlog 的 MySQL 作为 master:​

docker run -d -e MYSQL_ROOT_PASSWORD=123 mysql:5.7 mysqld --datadir=/var/lib/mysql --server-id=1 --log-bin=/var/lib/mysql/mysql-bin.log --gtid-mode=ON --enforce-gtid-consistency

创建数据库和表,并写入数据:​

mysql> create database ckdb;
mysql> use ckdb;
mysql> create table t1(a int not null primary key, b int);
mysql> insert into t1 values(1,1),(2,2);
mysql> select * from t1;
+---+------+
| a | b |
+---+------+
| 1 | 1 |
| 2 | 2 |
+---+------+
2 rows in set (0.00 sec)

ClickHouse Slave

目前以 database 为单位进行复制,不同的 database 可以来自不同的 MySQL master,这样就可以实现多个 MySQL 源数据同步到一个 ClickHouse 做 OLAP 分析功能。

创建一个复制通道:​

clickhouse :) CREATE DATABASE ckdb ENGINE = MaterializeMySQL('172.17.0.2:3306', 'ckdb', 'root', '123');
clickhouse :) use ckdb;
clickhouse :) show tables;
┌─name─┐
│ t1 │
└──────┘
clickhouse :) select * from t1;
┌─a─┬─b─┐
│ 1 │ 1 │
└───┴───┘
┌─a─┬─b─┐
│ 2 │ 2 │
└───┴───┘


2 rows in set. Elapsed: 0.017 sec.

看下 ClickHouse 的同步位点:
cat ckdatas/metadata/ckdb/.metadata​

Version:1
Binlog File:mysql-bin.000001
Binlog Position:913
Data Version:0

Delete

首先在 MySQL Master 上执行一个删除操作:​

mysql> delete from t1 where a=1;
Query OK, 1 row affected (0.01 sec)

然后在 ClickHouse Slave 侧查看记录:​

clickhouse :) select * from t1;


SELECT *
FROM t1


┌─a─┬─b─┐
│ 2 │ 2 │
└───┴───┘


1 rows in set. Elapsed: 0.032 sec.

此时的 metadata 里 Data Version 已经递增到 2:​

cat ckdatas/metadata/ckdb/.metadata
Version:1
Binlog File:mysql-bin.000001
Binlog Position:1171
Data Version:2

Update

MySQL Master:

mysql> select * from t1;
+---+------+
| a | b |
+---+------+
| 2 | 2 |
+---+------+
1 row in set (0.00 sec)


mysql> update t1 set b=b+1;


mysql> select * from t1;
+---+------+
| a | b |
+---+------+
| 2 | 3 |
+---+------+
1 row in set (0.00 sec)


ClickHouse Slave:

clickhouse :) select * from t1;


SELECT *
FROM t1


┌─a─┬─b─┐
│ 2 │ 3 │
└───┴───┘


1 rows in set. Elapsed: 0.023 sec.


实现机制

在探讨机制之前,首先需要了解下 MySQL 的 binlog event ,主要有以下几种类型:

1. MYSQL_QUERY_EVENT    -- DDL
2. MYSQL_WRITE_ROWS_EVENT -- insert数据
3. MYSQL_UPDATE_ROWS_EVENT -- update数据
4. MYSQL_DELETE_ROWS_EVENT -- delete数据

当一个事务提交后,MySQL 会把执行的 SQL 处理成相应的 binlog event,并持久化到 binlog 文件。

binlog 是 MySQL 对外输出的重要途径,只要你实现 MySQL Replication Protocol,就可以流式的消费MySQL 生产的 binlog event,具体协议见 Replication Protocol。

由于历史原因,协议繁琐而诡异,这不是本文重点。

对于 ClickHouse 消费 MySQL binlog 来说,主要有以下3个难点:

  • DDL 兼容
  • Delete/Update 支持
  • Query 过滤

DDL

DDL 兼容花费了大量的代码去实现。

首先,我们看看 MySQL 的表复制到 ClickHouse 后会变成什么样子。

MySQL master:

mysql> show create table t1\G;
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`a` int(11) NOT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1


ClickHouse slave:

ATTACH TABLE t1
(
`a` Int32,
`b` Nullable(Int32),
`_sign` Int8,
`_version` UInt64
)
ENGINE = ReplacingMergeTree(_version)
PARTITION BY intDiv(a, 4294967)
ORDER BY tuple(a)
SETTINGS index_granularity = 8192


可以看到:

  • 默认增加了 2 个隐藏字段:_sign(-1删除, 1写入) 和 _version(数据版本)
  • 引擎转换成了 ReplacingMergeTree,以 _version 作为 column version
  • 原主键字段 a 作为排序和分区键

这只是一个表的复制,其他还有非常多的DDL处理,比如增加列、索引等,感兴趣可以观摩 Parsers/MySQL 下代码。

Update和Delete

当我们在 MySQL master 执行:

mysql> delete from t1 where a=1;
mysql> update t1 set b=b+1;

ClickHouse t1数据(把 _sign 和 _version 一并查询):

clickhouse :) select a,b,_sign, _version from t1;


SELECT
a,
b,
_sign,
_version
FROM t1


┌─a─┬─b─┬─_sign─┬─_version─┐
│ 1 │ 1 │ 1 │ 1 │
│ 2 │ 2 │ 1 │ 1 │
└───┴───┴───────┴──────────┘
┌─a─┬─b─┬─_sign─┬─_version─┐
│ 1 │ 1 │ -1 │ 2 │
└───┴───┴───────┴──────────┘
┌─a─┬─b─┬─_sign─┬─_version─┐
│ 2 │ 3 │ 1 │ 3 │
└───┴───┴───────┴──────────┘


根据返回结果,可以看到是由 3 个 part 组成。

part1 由 ​​mysql> insert into t1 values(1,1),(2,2)​​ 生成:

┌─a─┬─b─┬─_sign─┬─_version─┐
│ 1 │ 1 │ 1 │ 1 │
│ 2 │ 2 │ 1 │ 1 │
└───┴───┴───────┴──────────┘

part2 由 ​​mysql> delete from t1 where a=1​​ 生成:​

┌─a─┬─b─┬─_sign─┬─_version─┐
│ 1 │ 1 │ -1 │ 2 │
└───┴───┴───────┴──────────┘
说明:
_sign = -1表明处于删除状态

part3 由 ​​update t1 set b=b+1​​ 生成:

┌─a─┬─b─┬─_sign─┬─_version─┐
│ 2 │ 3 │ 1 │ 3 │
└───┴───┴───────┴──────────┘

使用 final 查询:

clickhouse :) select a,b,_sign,_version from t1 final;


SELECT
a,
b,
_sign,
_version
FROM t1
FINAL


┌─a─┬─b─┬─_sign─┬─_version─┐
│ 1 │ 1 │ -1 │ 2 │
└───┴───┴───────┴──────────┘
┌─a─┬─b─┬─_sign─┬─_version─┐
│ 2 │ 3 │ 1 │ 3 │
└───┴───┴───────┴──────────┘


2 rows in set. Elapsed: 0.016 sec.


可以看到 ReplacingMergeTree 已经根据 _version 和 OrderBy 对记录进行去重。

Query

MySQL master:

mysql> select * from t1;
+---+------+
| a | b |
+---+------+
| 2 | 3 |
+---+------+
1 row in set (0.00 sec)


ClickHouse slave:

clickhouse :) select * from t1;


SELECT *
FROM t1


┌─a─┬─b─┐
│ 2 │ 3 │
└───┴───┘


clickhouse :) select *,_sign,_version from t1;


SELECT
*,
_sign,
_version
FROM t1


┌─a─┬─b─┬─_sign─┬─_version─┐
│ 1 │ 1 │ -1 │ 2 │
│ 2 │ 3 │ 1 │ 3 │
└───┴───┴───────┴──────────┘
说明:这里还有一条删除记录,_sign为-1

MaterializeMySQL 被定义成一种存储引擎,所以在读取的时候,会根据 _sign 状态进行判断,如果是-1则是已经删除,进行过滤。

总结

ClickHouse 实时复制同步 MySQL 数据是 upstream 2020 的一个 roadmap,在整体构架上比较有挑战一直无人接单,挑战主要来自两方面:

  • 对 MySQL 复制通道与协议非常熟悉
  • 对 ClickHouse 整体机制非常熟悉

这样,在两个本来有点遥远的山头中间架起了一座高速,这条 10851号 高速由 zhang1024(ClickHouse侧) 和BohuTANG(MySQL复制) 两个修路工联合承建,目前正在接受 upstream 的验收。

关于同步 MySQL 的数据,目前大家的方案基本都是在中间安置一个 binlog 消费工具,这个工具对 event 进行解析,然后再转换成 ClickHouse 的 SQL 语句,写到 ClickHouse server,链路较长,性能损耗较大。

10851号 高速是在 ClickHouse 内部实现一套 binlog 消费方案,然后根据 event 解析成ClickHouse 内部的 block 结构,再直接写回到底层存储引擎,几乎是最高效的一种实现方式。

基于 database 级的复制,实现了多源复制的功能,如果复制通道坏掉,我们只需在 ClickHouse 侧删除掉 database 然后再重建一次即可,非常方便。

对于单表的数据一致性,未来会实现一个 MySQL CRC 函数,用于校验 MySQL 与 ClickHouse 的数据一致性。

原文转自 https://bohutang.me/2020/07/26/clickhouse-and-friends-mysql-replication/

标签:MySQL,实时,t1,version,mysql,sign,ClickHouse
From: https://blog.51cto.com/u_15576159/5937991

相关文章

  • 基于Springboot+Mybatis+mysql+vue宠物领养网站1
    @目录一、系统介绍二、功能展示1.主页(普通用户)2.登陆、注册(普通用户)3.宠物大全(普通用户)4.宠物详情(申请领养、点赞、评论)(普通用户)5.我的申请(普通用户)6.个人信息(普通用户......
  • 基于jsp+sevlet+spring+mysql实现校园疫情防控管理信息系统
    @目录一、系统介绍二、采用技术及开发环境1.开发技术2.开发环境二、功能展示1.学校疫情统计2.各情况统计3.各学院学生情况统计4.各学院教师统计5.最新时报6.后台管理四、代......
  • jsp+sevlet+mysql图书管理系统
    @目录一、系统介绍二、功能展示1.图书查询(学生)2.借阅信息(学生)3.借阅历史(学生)4.借阅历史(管理员)5.读者管理(管理员)6.图书分类(管理员)7.图书借阅信息(管理员)8.图书......
  • mysql8权限控制
    CREATEUSER'test'@'xxx.xx.xx.%'IDENTIFIEDBY'123';grantallprivilegeson*.*to'test'@'xxx.xx.xx.%'IDENTIFIEDBY'123'withgrantoption;flushprivileg......
  • SpringBoot入门系列: JPA mysql(五)
    一,准备工作,建立spring-boot-sample-mysql工程1、http://start.spring.io/    A、Artifact中输入spring-boot-sample-mysql    B、勾选Web下的web    C、勾选......
  • 项目迁移中 遇到的MySQL问题
    两个问题都是数据库迁移导致的  1.Expression#16ofSELECTlistisnotinGROUPBYclauseandcontainsnonaggregatedcolumn'sanghe.a.contract_no'whichisno......
  • docker-compose + mysql8.x 主从数据库配置
    0.准备(略过docker的安装与镜像拉取)docker/docker-compose安装拉取mysql8.x 1.master和slave的mysql配置master:[mysqld]server-id=11118log-bin=mysql-bi......
  • OpenMLDB 实时引擎性能测试报告
    OpenMLDB提供了一个线上线下一致性的特征平台。其中,为了支持低延迟高并发的在线实时特征计算,OpenMLDB设计实现了一个高性能的实时SQL引擎。本报告覆盖了OpenMLDB实时......
  • Windows Defender 实时防护打不开,你的IT管理员已经限制对此应用一些区域的访问
        最近在使用电脑的时候,WindowsDefender实时防护不能使用,一打开就自动关闭,并且显示该页面不可用你的IT管理员已经限制对此应用一些区域的访问,实时防护页面显示......
  • MySQL 面试题总结
    MySQL的面试知识点总结Q1:MySQL的逻辑架构了解吗?第一层是服务器层,主要提供连接处理、授权认证、安全等功能。第二层实现了MySQL核心服务功能,包括查询解析、分析、优......