clickhouse 增量更新_ClickHouse王炸功能即将来袭?

众所周知,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的奇思妙想

往期精彩推荐:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/465540.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在批处理文件中启动MediaPlayer播放制定文件

我们知道在运行可以使用wmplayer指令来启动一个MediaPlayer,如果需要让MediaPlayer播放制定的文件或是一个制定的流媒体发布点,我们可以使用如下的命令格式wmplayer “mms://WIN-FW.MiGu.com/12530″wmplayer “C:\wmpub\wmroot\legacy_content_clip.wmv…

双重检查锁实现单例模式的线程安全问题

一、结论 双重校验锁的单例模式代码如下: public class Singleton {   private static Singleton singleton; private Singleton() {} public static Singleton getSingleton() {     if (singleton null) { // 1       synchronized (Singleton.clas…

摇杆控制方向原理_为工业安全守好”门”!各种方向的控制阀原理图大集合

单向的、换向的....你想了解的方向控制阀都在这里了!方向控制阀门液压阀是用来控制液压系统中油液的流动方向或调节其流量和压力的。方向控制阀作为液压阀的一种,利用流道的更换控制着油液的流动方向。单向型方向控制阀是只允许气流沿一个方向流动的方向…

对于新生代农民工,你有什么想说的?

昨晚上这个新闻很多人转,但是可能很少有人知道他的链接出处,链接来自于http://www.mohrss.gov.cn/SYrlzyhshbzb/jiuye/gzdt/202108/t20210816_420736.html我记得我还在上小学的时候,我们家有干不完的农活,暑假每天都要下田干活&am…

谁是经营之神

—北京维富友携手北京服装学院开展服装ERP沙盘大赛时间4月21日,地点北京服装学院,参加人数35人,参加人员北京维富友软件公司高级讲师、服装学院教师和同学共35人。目的:为了让学生更好的掌握服装企业管理和盈利管控,北…

在Android初次的前期学习中的二个小例子(2)

Hello13:SQLite数据库 一、简述SQLite的概念和主要特性SQLite是一个轻量级的关系型数据库,运算速度快,占用资源少,使用非常方便,支持SQL语法标准和数据库事务原则。相对于SharedPreferences使用文件保存数据,SQLite具有…

access 增加字段 工具_Java效率工具之Lombok

作者:LiWenD正在掘金来源:https://juejin.im/post/5b00517cf265da0ba0636d4b上一篇:数据库查询速度优化之解决技巧还在编写无聊枯燥又难以维护的POJO吗?洁癖者的春天在哪里?请看Lombok!在过往的Java项目中&…

一文读懂 | 进程并发与同步

并发 是指在某一时间段内能够处理多个任务的能力,而 并行 是指同一时间能够处理多个任务的能力。并发和并行看起来很像,但实际上是有区别的,如下图(图片来源于网络):concurrency-parallelism上图的意思是&a…

快速完成和读懂测试计划

每个项目测试计划都会不一样,但是一般情况下,每个公司都会有相应的模板,尤其是项目很频繁的公司,相对应的模板应该就更全面,并且更容易修改,更能适应新项目。 并且,经常接触测试计划的人可能会察…

rust卡领地柜权限_RFID智能医疗耗材柜,上海智能高值耗材柜,国药智能医用耗材柜...

近几年因为我们的医疗改革一直在进步并改革,国家对我们的医疗方面的补助也有了明显的加大投入,与此同时让各种公立私立医院如雨后春笋般层出不穷,各大医院为了在医疗市场占有一席之地,都在各个方面开始想办法提升自己医院的水准。…

刚接触电子时,有过哪些百思不得其解的问题?

青少年时期,刚接触电子时,出于好奇,对这方面的东西也比较关注,但同时也衍生了一些百思不得其解的疑问,比如...01物理书里说大地是导体,那为什么我的小灯珠却不亮!?02初三时学了物理的…

建立管理SQL Server登录帐户

1、打开SQL Server 2005的管理工具,选择以windows身份验证模式登陆。然后右击服务器选择属性。2、在打开的服务器属性页面中,选择“安全性”做如下图设置:3.在windows上新建三个组:ReceptionEmployees,ITEmployees。4、然后在SQL …

属性

属性 属性的作用就是保护字段、对字段的赋值和取值进行限定。 属性的本质就是两个方法,一个叫get()一个叫set()。 既有get()也有set()我们诚之为可读可写属性。 只有get()没有set()我们称之为只读属性 没有get()只有set()我们称之为只写属性 private char _gender; …

c++ doxygen 注释规范_利用Doxygen给C程序生成注释文档

利用Doxygen为C程序生成注释文档一、Doxygen工具的安装利用Doxygen工具生成API帮助文档需要下载安装以下三个软件:(1)Doxygen:可以从一套归档源文件开始,生成HTML格式的在线类浏览器,或离线的LATEX、RTF参考手册。本文中所使用的版…

【2021新版】一线大厂 Go 面试题合集

秋天到了,又到了工程师们躁动不安,蠢蠢欲动的季节~这不,金九银十已然到了家门口,现在后台就有不少人问我:现在外边大厂面试都问啥想去大厂又怕面试挂面试应该怎么准备Go 开发前景如何啥样的后端适合切 Go 技术栈...面试…

python开发【基础二】

基本数据类型: 1、数字 在Python2中,分为整形(int)和长整形(long)。 在Python3中,都是int。 #1、将字符串转换为数字 a "123" v int(a) print(v) print(type(v))#2、当前数字的二进制,至少用几位表示 1位等于8个字节.…

微软白皮书发布:在IIS7.5中用Service Bus端点寄宿WCF服务

公告:本博客为微软云计算中文博客的镜像博客。部分文章因为博客兼容性问题,会影响阅读体验。如遇此情况,请访问原博客。 针对如何在IIS中寄宿Service Bus的问题,微软官方提供了白皮书详细介绍了解决方案。有兴趣的读者可以从下面的…

oracle数据库时分秒格式_Oracle如何输出指定格式的日期时间数据呢?

摘要:下文讲述Oracle数据库输出指定的日期时间格式的方法分享,如下所示;实现思路:使用TO_CHAR系统函数,指定输出格式为*******,即可将日期时间转换为指定格式的字符串如:SELECT TO_CHAR(SYSDATE,YYYY/MM/DD) AS MONTH …

can总线资料

应知识星球的同学要求,整理了一些can总线资料。在公众号后台回复 【can总线】获取资料截图推荐阅读:专辑|Linux文章汇总专辑|程序人生专辑|C语言我的知识小密圈

Go语言基础之4--流程控制

一、if else语句 1.1 基本语法1 语法1: if condition { //do something } 语法2: if condition { //do something } else { //do something } 语法3: if condition { //do something } else if condition { //do something } else { //do som…