众所周知,MySQL 的用户群体很大,为了能够增强数据的实时性,很多解决方案会利用 binlog 将数据写入到 ClickHouse。

为了能够监听 binlog 事件,我们需要用到类似 canal 这样的第三方中间件,这无疑增加了系统的复杂度。

在不久的将来,这一现状可能会发生改观。因为目前,编号 10851 的 PR 进入了 review 阶段。

(https://github.com/ClickHouse/ClickHouse/pull/10851)

该 PR 将为 ClickHouse 带来原生消费 binlog 日志的能力,是不是王炸功能?

这次是新增了一个名为 MaterializeMySQL 的 database 引擎,该 database 能映射到 MySQL 中的某个 database,并自动在 ClickHouse 中创建对应的 ReplacingMergeTree。

MaterializeMySQL 同时支持全量和增量同步,在 database 创建之初会全量同步 MySQL 中的表和数据,之后则会通过 binlog 进行增量同步。

MaterializeMySQL database 为其所创建的每张 ReplacingMergeTree 自动增加了 _sign 和 _version 字段。

其中, _version 用作 ReplacingMergeTree 的 ver 版本参数,每当监听到 insert、update 和 delete 事件时,在 databse 内全局自增。而 _sign 则用于标记是否被删除,取值 1 或者 -1。

目前 MaterializeMySQL 支持如下几种 binlog 事件:

MYSQL_WRITE_ROWS_EVENT

_sign = 1,_version ++

MYSQL_DELETE_ROWS_EVENT

_sign = -1,_version ++

MYSQL_UPDATE_ROWS_EVENT

新数据 _sign = 1

MYSQL_QUERY_EVENT

支持 CREATE TABLE 、DROP TABLE 、RENAME TABLE等。

虽然该 PR 目前还没有被 merge 到主线,但是我已忍不住想要尝鲜,接下来就让我们一睹它的芳容吧。

首先准备一个 MySQL 实例

#拉取镜像docker pull mysql:5.7.31#运行镜像docker run -p 3306:3306 --name mysql5.7 -v {your-path}/mysql/conf:/etc/mysql -v {your-path}/mysql/logs:/logs -v {your-path}/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7.31

确保 MySQL 开启了 binlog 功能,且格式为 ROW

#conf/my.cnfserver-id=1# Uncomment the following if you want to log updateslog-bin=mysql-bin# binary logging format - mixed recommended#binlog_format=mixedbinlog_format=ROW

现在开始测试,首先在 MySQL 中创建数据表并写入数据

CREATE TABLE `t_organization` (`id` int(11) NOT NULL AUTO_INCREMENT,`code` int NOT NULL,`name` text DEFAULT NULL,`updatetime` datetime DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY (`code`)) ENGINE=InnoDB;INSERT INTO t_organization (code, name,updatetime) VALUES(1000,'Realinsight',NOW());INSERT INTO t_organization (code, name,updatetime) VALUES(1001,'Realindex',NOW());INSERT INTO t_organization (code, name,updatetime) VALUES(1002,'EDT',NOW());

继续创建第二张表

CREATE TABLE `t_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`code` int,PRIMARY KEY (`id`)) ENGINE=InnoDB;INSERT INTO t_test (code) VALUES(1);

现在轮到 ClickHouse 这边了,创建  MaterializeMySQL 数据库

CREATE DATABASE test_binlog ENGINE = MaterializeMySQL('127.0.0.1:3306','htap','root','root');

其中 4 个参数分别是 MySQL地址、databse、username 和 password。

执行之后可以观察一下它执行日志

2020.07.2020.07.29 01:29:53.571991 [ 868116 ] {} executeQuery: (internal) /*Materialize MySQL step 1: execute MySQL DDL for dump data*/ EXTERNAL DDL FROM MySQL(test_binlog, htap) CREATE TABLE `t_organization` ( `id` int(11) NOT NULL AUTO_INCREMENT, `code` int(11) NOT NULL, `name` text, `updatetime` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `code` (`code`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf82020.07.29 01:29:53.577595 [ 868116 ] {}  executeQuery: (internal) /* Rewritten MySQL DDL Query */ CREATE TABLE test_binlog.t_organization (`id` Int32, `code` Int32, `name` Nullable(String), `updatetime` Nullable(DateTime), `_sign` Int8, `_version` UInt64) ENGINE = ReplacingMergeTree(_version) PARTITION BY intDiv(id, 4294967) ORDER BY (code, id)

可以看到,ClickHouse dump 出了 MySQL 的表结构,并将其转换成了 ReplacingMergeTree。

在这个过程中,不仅各字段的数据类型进行了映射,还多出了 _sign 和 _version 两个字段。

MySQL 表的 PRIMARY KEY 作为了 ReplacingMergeTree 的 PARTITION BY,并且按照类型大小除以1000整除;

MySQL 表的  PRIMARY KEY 同时也作为了 ReplacingMergeTree 的 ORDER BY,如果 MySQL 表中还有 UNIQUE KEY (此例中的 code 字段),它也会一同被加入到 ORDER BY。

现在我们查询 ClickHouse 的 test_binlog 数据库

use test_binlog;show tables;┌─name───────────┐│ t_organization ││ t_user │└────────────────┘

MySQL 的表已经被同步过来了,接着试试查询数据

select * from t_organization;SELECT *FROM t_organization┌─id─┬─code─┬─name────────┬──────────updatetime─┐│ 1 │ 1000 │ Realinsight │ 2020-07-28 17:29:47 │└────┴──────┴─────────────┴─────────────────────┘┌─id─┬─code─┬─name──────┬──────────updatetime─┐│ 2 │ 1001 │ Realindex │ 2020-07-28 17:29:48 │└────┴──────┴───────────┴─────────────────────┘┌─id─┬─code─┬─name─┬──────────updatetime─┐│ 3 │ 1002 │ EDT │ 2020-07-28 17:29:49 │└────┴──────┴──────┴─────────────────────┘3 rows in set. Elapsed: 0.032 sec.

接下来进一步测试 binlog 的同步功能。

首先在 MySQL 中修改数据:

update t_organization set name = CONCAT(name,'-v1') where id = 1

查看 ClickHouse 日志会发现 binlog 监听事件:

=== UpdateRowsEventV2 ===Timestamp: 1595958048Event Type: 31Server ID: 1Event Size: 93Log Pos: 20454Flags: 0Schema: htapTable: t_organizationRow[0]: (1, 1000, 'Realinsight', 1595928587)Row[1]: (1, 1000, 'Realinsight-v1', 1595928587)

查询 ClickHouse 的数据表:

select * from t_organization;┌─id─┬─code─┬─name───────────┬──────────updatetime─┐│ 1 │ 1000 │ Realinsight-v1 │ 2020-07-28 17:29:47 │└────┴──────┴────────────────┴─────────────────────┘┌─id─┬─code─┬─name──────┬──────────updatetime─┐│ 2 │ 1001 │ Realindex │ 2020-07-28 17:29:48 │└────┴──────┴───────────┴─────────────────────┘┌─id─┬─code─┬─name─┬──────────updatetime─┐│ 3 │ 1002 │ EDT │ 2020-07-28 17:29:49 │└────┴──────┴──────┴─────────────────────┘

可以看到 id = 1的数据被修改了。

现在再次回到 MySQL,尝试删除数据:

DELETE FROM t_organization where id = 2

回到 ClicKHouse,同样会发现 DeleteRows 的 binlog 监听事件:

=== DeleteRowsEventV2 ===Timestamp: 1595958230Event Type: 32Server ID: 1Event Size: 60Log Pos: 20744Flags: 0Schema: htapTable: t_organizationRow[0]: (2, 1001, 'Realindex', 1595928588)

查询 ClickHouse的 t_organization:

select * from t_organization;SELECT *FROM t_organization┌─id─┬─code─┬─name───────────┬──────────updatetime─┐│ 1 │ 1000 │ Realinsight-v1 │ 2020-07-28 17:29:47 │└────┴──────┴────────────────┴─────────────────────┘┌─id─┬─code─┬─name─┬──────────updatetime─┐│ 3 │ 1002 │ EDT │ 2020-07-28 17:29:49 │└────┴──────┴──────┴─────────────────────┘

id = 2 的数据被删除了。

这是怎么实现的呢?  在刚才的查询中增加 _sign 和 _version 虚拟字段,一切将会真相大白。

select *,_sign,_version from t_organization order by _sign desc,_version descSELECT*,_sign,_versionFROM t_organizationORDER BY_sign DESC,_version DESC┌─id─┬─code─┬─name───────────┬──────────updatetime─┬─_sign─┬─_version─┐│ 1 │ 1000 │ Realinsight-v1 │ 2020-07-28 17:29:47 │ 1 │ 2 │└────┴──────┴────────────────┴─────────────────────┴───────┴──────────┘┌─id─┬─code─┬─name────────┬──────────updatetime─┬─_sign─┬─_version─┐│ 1 │ 1000 │ Realinsight │ 2020-07-28 17:29:47 │ 1 │ 1 ││ 2 │ 1001 │ Realindex │ 2020-07-28 17:29:48 │ 1 │ 1 ││ 3 │ 1002 │ EDT │ 2020-07-28 17:29:49 │ 1 │ 1 │└────┴──────┴─────────────┴─────────────────────┴───────┴──────────┘┌─id─┬─code─┬─name──────┬──────────updatetime─┬─_sign─┬─_version─┐│ 2 │ 1001 │ Realindex │ 2020-07-28 17:29:48 │ -1 │ 3 │└────┴──────┴───────────┴─────────────────────┴───────┴──────────┘5 rows in set. Elapsed: 0.048 sec.

在查询时,对于已经被删除的数据,ClickHouse 会自动重写 SQL,将 _sign = -1 的数据过滤掉;

对于修改的数据,则自动重写 SQL,为其增加 FINAL 修饰符。

select * from t_organization等同于select * from t_organization final where _sign = 1

在 20.5 版本中,final 查询已经支持多线程,性能有很大的提升。

大家应该会发现,目前在 ReplacingMergeTree 中被删除的数据只是被过滤掉了,并没有物理删除。经与作者大神 zhang2014 咨询,将来会通过类似 GC 的思路通过另外的线程定期删除 _sign = -1 的数据。

这项功能如果被 merge 进主线,无疑会增强 ClicKHouse 更加自动化的属性。

如果这篇文章对你有帮助,欢迎点赞、转发、在看三连击 :)

欢迎大家扫码关注我的

公众号和视频号

:

ClickHouse的秘密基地

nauu的奇思妙想

往期精彩推荐:

clickhouse 增量更新_ClickHouse王炸功能即将来袭?相关推荐

  1. clickhouse 增量更新_Clickhouse單機部署以及從mysql增量同步數據

    背景: 隨着數據量的上升,OLAP一直是被討論的話題,雖然druid,kylin能夠解決OLAP問題,但是druid,kylin也是需要和hadoop全家桶一起用的,我也搞不定,那只能找我能搞定的技術 ...

  2. 微信 8.0 重大更新,王炸!!!

    作者 | JiekeXu 来源 | JiekeXu之路(ID: JiekeXu_IT) 转载请联系授权 | (微信ID:xxq1426321293) 大家好,我是 JiekeXu,分开这么久,很高兴又 ...

  3. clickhouse 增量更新_干货 | 每天十亿级数据更新,秒出查询结果,ClickHouse在携程酒店的应用...

    本文转自| 携程技术中心  作者 | 蔡岳毅 作者简介蔡岳毅,携程酒店大数据高级研发经理,负责酒店数据智能平台研发,大数据技术创新工作.喜欢探索研究大数据的开源技术框架.一.背景 1)携程酒店每天有上 ...

  4. Github 王炸功能!Copilot 替代打工人编程?

    大家好,我是若川.最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 参与,已进行三个月了,大家一起交流学习,共同进步. 大家好,我是皮汤.最近组里在讨论一个有意思的工具 Github ...

  5. 评价最高影片JAVAlibrary_三大“百亿影帝”联袂主演,一部比肩《战狼》的王炸影片即将诞生...

    在华语电影近百年发展史当中,<战狼2>是一部不得不提的电影,吴京是一位不得不提的艺人,因为<战狼2>开创了华语动作大片的时代,让国产电影首次走出国门,走向世界,因为居功至伟,该 ...

  6. 【clickhouse】clickhouse强大智能的 Projection (投影) 功能

    1.概述 转载:ClickHouse王炸功能来袭,性能轻松提升40倍 各位,今年 ClickHouse 最王炸的功能来啦,没错,就是期待已久的 Projection (投影) 功能.ClickHous ...

  7. Android增量更新框架

    Android增量更新框架 框架介绍 功能简介 简易效果图 增量更新配置 快速使用 Api详解 项目地址 框架介绍 功能简介 Android App更新框架,包含增量更新.多线程下载等功能.一句代码链 ...

  8. clickhouse初学以及利用ck实现BI系统的增量更新

    文章目录 概述 适用场景 库引擎(部分) 1.Atomic 2.Lazy 3.Mysql.SQLite.PostergreSQL等一系列 数据类型(部分) 表引擎-合并树系列 ReplacingMer ...

  9. 天气预报查询 API + AI 等于王炸(一大波你未曾设想的天气预报查询 API 应用场景更新了)

    前言 近年来,随着信息化进程的不断深入,人们对于信息的获取和处理需求越来越高.而其中,天气查询API是一个非常重要的服务,它能够帮助人们快速获取所在位置的天气情况,同时也为各类应用提供了必要的气象数据 ...

最新文章

  1. 三种方式实现日志记录
  2. Qt中ui文件的使用
  3. 如何获取 SAP Commerce Cloud Spartacus UI 购物车 Cart 的加载状态
  4. 理正地基基础计算机辅助设计的英文缩写,理正基础CAD软件介绍理正基础CAD软件介绍.pdf...
  5. 源码分享,送你一份Google Python class源码
  6. java扫描指定package注解_java获取包下被指定注解的类
  7. Python tarfile模块(压缩解压tar)
  8. CF1025C Plasticine zebra
  9. 大数据时代,百货行业信息化将如何变革?
  10. solr 使用记录 - solr dataimporter 定时任务
  11. 数据库的表连接和函数学习
  12. POI 实现Word表格合并单元格(行合并)
  13. MyEclipse 10 破解
  14. 流利阅读day1 Dysmorphia
  15. 基于云服务创建离线数据统计分析服务(一)
  16. 拿到一个网站,怎么判断该网站是否存在sql注入漏洞?
  17. maven 程序包不存在 https://repo.maven.apache.org/maven2 was cac hed in the local repository
  18. `Computer-Algorithm` 二分图BipartiteGraph,最大匹配,最小点覆盖,最大独立集
  19. 个人python学习(10)
  20. 玩转安卓 Android系统文件夹结构解析(绝对有用)

热门文章

  1. CLR Via CSharp读书笔记(7):常量和字段
  2. IP SLA的路径控制
  3. 【2022】多线程并发编程面试真题
  4. 使用@Order调整配置类加载顺序
  5. Java笔记02-OOP
  6. 关于 HTTP 的一切(HTTP/1.1,HTTP/2,HTTP/3,HTTPS, CORS, 缓存 ,无状态)
  7. 剑指offer:二叉树中和为某一值的路径
  8. uboot源码——C阶段的start_armboot函数
  9. mysql命令导出数据库_MYSQL 数据库导入导出命令
  10. Android MVP模式简单易懂的介绍方式 (一)