Trino连接ClickHouse代码浅析

2022-05-20 08:50:54 浏览数 (2)

最近在调研Trino和Clickhouse的打通问题,简单研究了下Trino对于CH的适配,这里简单总结下。详细的代码提交参见这个commit:Add ClickHouse Connector。

加载Plugin

Trino在启动的时候,会加载所有已经支持的plugin,也就是说常说的connector,加载的路径位于plugin/下,如下所示:

可以看到,目前支持的plugin种类非常多,有40多个。这里以CH为例,加载完成之后,服务端会打印相应的日志:

代码语言:javascript复制
2022-02-08T16:57:26.445 0800	INFO	main	io.trino.server.PluginManager	-- Loading plugin /data/impala/presto/data/plugin/clickhouse --
2022-02-08T16:57:26.463 0800	INFO	main	io.trino.server.PluginManager	Installing io.trino.plugin.clickhouse.ClickHousePlugin
2022-02-08T17:37:26.845 0800    INFO    main    io.trino.server.PluginManager   Registering connector clickhouse
2022-02-08T16:57:26.472 0800    INFO    main    io.trino.server.PluginManager   -- Finished loading plugin /data/impala/presto/data/plugin/clickhouse --

可以看到,这里主要就是加载了ClickHousePlugin这个类,相关的函数调用栈如下所示:

代码语言:javascript复制
doStart(Server.java):126
-loadPlugins(PluginManager.java):129
--loadPlugins(ServerPluginsProvider.java):58
---loadPlugin(PluginManager.java):148
---loadPlugin(PluginManager.java):162
----installPlugin(PluginManager.java):168
-----installPluginInternal(PluginManager.java):191
------addConnectorFactory(ConnectorManager.java)

在服务启动之后,会先注册相应的ConnectorFactory,这里涉及到了比较多的类,我们将相关类的UML图简单整理了下:

ConnectorFactory里面就包含对应的plugin,对于CH而言,ClickHousePlugin。Plugin本身又包含了对应的ConnectionFactory。最终,对于CH的plugin来说,就是使用了ClickHouseDriver去连接CH集群的。后续再进行各种元数据加载和查询的时候,就会利用这个connection来与CH集群进行交互,如下所示:

加载ClickHouse元数据

下面简单来看下Trino是如何加载catalog的。简单的代码调用栈如下所示:

代码语言:javascript复制
doStart(Server.java):128
-loadCatalogs(StaticCatalogStore.java):68
--loadCatalog(StaticCatalogStore.java)

默认配置在服务端路径的etc/catalog/下,以“.properties”结尾的所有文件,如下所示:

通过循环加载每个catalog对应的配置文件,如下所示:

代码语言:javascript复制
for (File file : listFiles(catalogConfigurationDir)) {
    if (file.isFile() && file.getName().endsWith(".properties")) {
        loadCatalog(file);
    }
}

private File catalogConfigurationDir = new File("etc/catalog/");

这里同样以ClickHouse为例,常见的配置如下:

代码语言:javascript复制
connector.name=clickhouse
connection-url=jdbc:clickhouse://host:8123/
connection-user=xxx
connection-password=xxx
allow-drop-table=true
case-insensitive-name-matching=true

当服务启动之后,同样会打印相关的日志,如下所示:

代码语言:javascript复制
2022-02-08T16:13:31.644 0800    INFO    main    io.trino.metadata.StaticCatalogStore    -- Loading catalog etc/catalog/clickhouse.properties --
2022-02-08T16:13:32.098 0800    WARN    main    ru.yandex.clickhouse.ClickHouseDriver   ******************************************************************************************
2022-02-08T16:13:32.098 0800    WARN    main    ru.yandex.clickhouse.ClickHouseDriver   * This driver is DEPRECATED. Please use [com.clickhouse.jdbc.ClickHouseDriver] instead.  *
2022-02-08T16:13:32.098 0800    WARN    main    ru.yandex.clickhouse.ClickHouseDriver   * Also everything in package [ru.yandex.clickhouse] will be removed starting from 0.4.0. *
2022-02-08T16:13:32.098 0800    WARN    main    ru.yandex.clickhouse.ClickHouseDriver   ******************************************************************************************
2022-02-08T16:13:32.270 0800    INFO    main    io.trino.metadata.StaticCatalogStore    -- Added catalog clickhouse using connector clickhouse --

根据上面的Plugin加载流程可以知道,Trino会根据这些配置项利用ClickHouseDriver来构造CH的Connection,进而进行各种操作。 例如,当我们通过show tables查看CH集群指定db下的表时,就会通过ClickHouseClient中的方法来执行,相关代码如下所示:

代码语言:javascript复制
public ResultSet getTables(Connection connection, Optional<String> schemaName, Optional<String>   
    tableName) throws SQLException
{
  // ClickHouse maps their "database" to SQL catalogs and does not have schemas
  DatabaseMetaData metadata = connection.getMetaData();
  return metadata.getTables(null,schemaName.orElse(null),
      escapeNamePattern(tableName, metadata.getSearchStringEscape()).orElse(null),
      new String[] {"TABLE", "VIEW"});
}

相关的类图如下所示:

这里CH对应的就是ClickHouseClient。

查询ClickHouse数据

当执行查询的时候,也是通过CH的jdbc来执行的,首先会通过ClickHouseClient来构造一个PreparedStatement,相关的调用栈如下所示:

代码语言:javascript复制
buildSql(BaseJdbcClient.java):380
-prepareStatement(QueryBuilder.java):185
--getPreparedStatement(BaseJdbcClient.java):763  --实际当前是ClickHouseClient类型
---prepareStatement(ForwardingConnection.java):54
----prepareStatement(ClickHouseConnectionImpl.java)

后续就会通过PreparedStatement.executeQuery()来执行真正的查询,所以,对于CH的查询来说,Trino还是通过JDBC来让CH自己去查询。关于整个查询流程的代码,后续有空再深入研究。

0 人点赞