Clickhouse的MySQL外部表,坑货!

来源:安瑞哥是码农

这两天的主要精力一直在思考,如何把外部的MySQL、SQLServer数据源高效、优雅的导入到Clickhouse(下称CK)中。


要说高效,其实用CK自带的外部表+物化视图的方式一定是最快的、最省事的。


因为之前用过kafka的外部表+物化视图的方式,就可以很方便把外部数据给导入到CK内部,确实很好用,可是这一次,我们把kafka换成MySQL之后,到底还能不能好使呢?


那么这篇文章,咱就来看看,CK支持的mysql外部表,到底能不能行。



0. MySQL外部表种类


针对MySQL的外部表,官方文档说明中至少有3种玩法,前两种是专门针对MySQL的 MySQL 引擎表和 MaterializedMySQL 引擎库,还有第三种,则是基于JDBC的外部引擎表。



那么针对这两种方式的外部表如何玩,这其中到底有没有坑,接下来我们一起来实地考察一番。



1. MySQL引擎表


先来看CK专门针对MySQL数据库而提供的外部表功能,相比后面的JDBC方式,这是一种目前CK提供的,跟MySQL数据库建立关联最简单的方式。


具体玩法,就跟建普通的CK本地表一样,只不过,需要把表的引擎给换成MySQL,比如像这样:


CREATE TABLE mysql_data01
(
    `id` int,
    `name` String
)
ENGINE = MySQL('192.168.211.106''test''test01''xxx''xxxxx')

括号里面的参数依次是:MySQL数据库的ip,库名,表名,用户名,密码。


建成之后,此时的CK命令行界面,就好比MySQL的一个客户端,你就可以直接通过这个表名,来查询到MySQL对应的test01这张表的数据了。


但是,你知道,这肯定不是我的目的,因为既然是客户端,那么就说明该表的数据仅仅只是拉到我当前CK实例的内存里,而并没有写入我的CK存储中。


这个时候,我就需要在CK创建一张真实的物理表,然后通过某种方式把这个MySQL的数据给灌到这个真实的物理表中。


那么这个「某种方式」,官方最推荐的做法就是创建一个物化视图,它可以把MySQL表中的数据,根据写入变化(物化视图目前只支持insert),实时同步到CK的物理表中,类似给它们之间架起了一座数据传输管道。


于是,我就创建了CK本地表:


再又创建MySQL(test01)表跟CK本地表(mysql2ck_local01)之间的物化视图:


按理说,这个时候我只要往MySQL表里写数据,就可以从这张CK的本地表或者物化视图里查到对应的数据。


可遗憾的是,当我往MySQL表写了几条数据之后,并没有得到我期待的结果:


MySQL映射表有数据

物化视图没有数据


本地表亦没有数据


所以我宣布,用MySQL外部表+物化视图的方式来同步MySQL表数据失败。

PS:后面我又尝试用了物化视图的POPULATE方式,虽然可以把mysql的历史数据全部导入到CK本地表,但后续mysql增加的数据,就导入不了了,所以还是不行。



2. MaterializedMySQL引擎库


顺着官方文档往后翻,发现它还提供了一个支持MySQL全库同步的方式,那就是创建一个 MaterializedMySQL 引擎库(注意是库,而非表),这样就可以把MySQL特定库下的所有表都同步到CK里。


只不过,这是CK推出的一个实验性功能,虽然如此,但我还是决定一试。


大概查了一下原理,这种玩法,其实是利用了MySQL的binlog功能,通过日志变化来同步数据的变化。


所以这种玩法也就意味这需要对原本的MySQL数据库做一些配置的改变(比如需要开启原本默认关闭的binlog功能)。


只是不幸的是,我当前的MySQL为5.5版本(centos7自带的版本),好像没办法识别官方文档给的那些需要额外添加的MySQL配置。


需要添加的配置



当前mysql无法识别

既然这样,只好作罢,说明这一招并不是在所有的MySQL版本上都奏效,下次我再换个高版本的再试试。


所以,果然是实验性的,不靠谱。



3. JDBC引擎表


通过官方文档,现在貌似只剩最后一招了,那就是试试通过JDBC引擎表+物化视图的方式,看看得不得行。


之所以把这部分放到最后来写,原因在于想要使用JDBC引擎,相比上面的2个引擎操作,要更麻烦一些,它需要额外启动一个JDBC-Bride服务


运行原理大致是这样的:


官网copy过来的图

也就是如果想要在CK中查询支持JDBC协议的外部表,必须要通过JDBC-Bride这么个中间服务才可以。


具体的部署方式呢,其实有3种(详见: https://github.com/ClickHouse/clickhouse-jdbc-bridge):


1. docker方式部署;


2. RPM包安装;


3. Java程序包运行。


官方文档用的第3种,而我为了更方便,用的第2种部署方式:


rpm包部署方式


用rpm包部署最大的好处在于,相关的配置文件和目录在部署的时候就已经给你自动生成好了,不需要再额外去创建。


下面这个目录,就是用rpm包部署后自动生成的配置目录:



现在我们最关心的,就是如何来使用这个jdbc-bride。


既然是通过它来连接数据库,那是不是就必须得有对应数据库的配置才行,跟上面直接在建表语句中配置数据源信息不一样的是,这个jdbc-bridge的玩法,需要在专门的配置文件中。


在哪呢?搁着藏着呢(官方文档其实没有说明,被我摸索找到的):


这个目录下,对应的json文件,就是你目标数据库的配置,比如我的这个数据源就是MySQL(版本为5.5),对应配置文件为mysql5.5.json(取什么名字不重要,你能区别就行)。


对应配置内容如下:


{
  "mysql5.5": {
  "driverUrls": [
    "https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.9/mysql-connector-java-5.1.9.jar"
  ],
  "jdbcUrl""jdbc:mysql://192.168.211.106:3306",
  "username""***",
  "password""***"
  }
}

这个配置中,「mysql5.5」代表的数据源的名称,这个在后面查询语句里需要用到,而这个 driverUrls 则可以改为本地的jar包路径。


这种不同的数据库源,用不同的配置文件来分别表示,最大的好处在于,可以随着数据库版本的不一样,设置不同版本需要的jar包,避免了用同一种连接方式面对不同版本数据库时,无法兼容的情况。


启动jdbc-bridge服务:


数据库源的配置文件设置好之后,接下来就是启动该服务,很简单,直接在命令行敲如下命令即可(这就是RPM部署的好处之一):


从启动的输出中可以看出来,刚才配置的mysql5.5数据源已经被加载了。


如何用呢?


服务跑起来了,那么现在就可以在CK的客户端直接通过JDBC的方式查询到mysql5.5数据源的数据了。


这种是直接利用jdbc函数,通过指定数据源名称、库名、表名参数的方式就能查询到对应表的数据。


还有一招,那就是通过创建JDBC引擎表来查数据:


创建JDBC引擎表

通过JDBC引擎表查询

至此,这个JDBC引擎的初步功能算是已经实现了。


但是不知道你有没有发现一个问题,那就是这个jdbc-bridge服务,当前我是部署在跟CK同一台机器上的,那如果把它部署到其他地方,是不是我的CK就找不到它了(默认会在本机找)。


那这个时候,就需要在CK的主配置文件/etc/clickhouse-server/config.xml中,添加(修改)如下配置:


如何导数据到CK表?


上面提到的查询,还都只是CK充当一个jdbc的客户端,并没有把mysql的数据给导入到CK中来(可以通过查看实际数据存储的目录来判断),那怎么样才能把它给倒腾过来呢?


我能想到的就是再创建一张CK本地表,然后再通过创建一个物化视图,把这个数据给引过来。


先建本地表:


再建物化视图:


然后,我再往mysql的表(mysql_data02)写入一些数据后发现。


物化视图居然查不到(本地表也一样):


就让人很生气。


随后,我又顺着官方文档往后翻,又发现了CK一些其他的骚操作,比如像什么动态视图(Live view)、窗口视图(Window view)等。


我都替大家一一试了一遍,虽然效果确实比较花,但在实现上还是只能停留在CK作为客户端这个基础上,我个人会肤浅的认为,这玩意并不实用,至少不能解决我眼下的问题。



最后


这篇文章的初衷呢,是想利用mysql的外部表+物化视图的方式,看能不能顺利把mysql原表的数据给导入到CK的(模仿之前kafka的玩法),但是几经折腾后发现,不行(当然,也有可能是我水平不行)。


核心问题是,这种方式不能同步mysql源表的增量数据(历史数据用 POPULATE 方式是可以的),所以也就失去了作为mysql数据源同步方案之一的资格。


那咋整?


正如上篇文章写到的,我暂时用DataX。


请使用浏览器的分享功能分享到微信等