快速开发ClickHouse应用
ClickHouse是面向联机分析处理的列式数据库,支持SQL查询,且查询性能好,特别是基于大宽表的聚合分析查询性能非常优异,比其他分析型数据库速度快一个数量级。
ClickHouse的设计优点:
- 数据压缩比高
- 多核并行计算
- 向量化计算引擎
- 支持嵌套数据结构
- 支持稀疏索引
- 支持数据Insert和Update
ClickHouse的应用场景:
MRS对外提供了ClickHouse JDBC的应用开发样例工程,本实践用于指导您创建MRS集群后,获取并导入样例工程并在本地进行编译调测,用于实现MRS集群中的ClickHouse的表创建、删除以及数据的插入、查询等操作。
创建MRS ClickHouse集群
- 购买一个包含有ClickHouse组件的MRS集群,详情请参见购买自定义集群。
本文以购买的MRS 3.2.0-LTS.1版本的集群为例,组件包含ClickHouse组件,集群开启Kerberos认证。
- 单击“立即购买”,等待MRS集群创建成功。
准备应用程序认证用户
对于开启Kerberos认证的MRS集群,需提前准备具有相关组件操作权限的用户用于程序认证。
以下ClickHouse权限配置示例供参考,在实际业务场景中可根据业务需求灵活调整。
- 集群创建成功后,登录FusionInsight Manager。
- 在FusionInsight Manager界面选择
。
- 填写角色的名称,例如developrole,单击“确定”保存角色。
- 在“配置资源权限”的表格中选择“待操作集群的名称 > ClickHouse > Clickhouse管理员权限”。
- 选择
,创建一个人机用户,例如developuser,“角色”加入developrole。
用户创建成功后,使用该用户登录FusionInsight Manager,根据界面提示修改初始密码。
获取样例工程
- 通过开源镜像站获取样例工程。
下载样例工程的Maven工程源码和配置文件,并在本地配置好相关开发工具,可参考通过开源镜像站获取样例工程。
根据集群版本选择对应的分支,下载并获取MRS相关样例工程。
例如本章节场景对应示例为“clickhouse-examples”样例,获取地址:https://github.com/huaweicloud/huaweicloud-mrs-example/tree/mrs-3.2.0.1/src/clickhouse-examples。
- 本地使用IDEA工具导入样例工程,等待Maven工程下载相关依赖包,具体操作可参考配置并导入样例工程。
图1 ClickHouse样例工程示例
本地配置好Maven及SDK相关参数后,样例工程会自动加载相关依赖包。
- 在本示例工程中,程序通过配置文件中的IP地址信息及用户信息与ClickHouse服务端进行连接。因此工程导入完成后,需要修改样例工程的“conf”目录下的“clickhouse-example.properties”文件,根据实际环境信息修改相关参数。
loadBalancerIPList=192.168.64.10,192.168.64.122 sslUsed=true loadBalancerHttpPort=21425 loadBalancerHttpsPort=21426 CLICKHOUSE_SECURITY_ENABLED=true user=developuser #密码明文存储存在安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全 password=用户密码 isMachineUser=false isSupportMachineUser=false clusterName=default_cluster databaseName=testdb tableName=testtb batchRows=10000 batchNum=10 clickhouse_dataSource_ip_list=192.168.64.10:21426,192.168.64.122:21426 native_dataSource_ip_list=192.168.64.10:21424,192.168.64.122:21424
表1 配置说明表 配置名称
描述
loadBalancerIPList
ClickHouseBalancer实例的地址信息。
登录FusionInsight Manager,选择“集群 > 服务 > ClickHouse > 实例”,可查看实例对应的IP地址。
例如本示例中,配置为“192.168.64.10,192.168.64.122”。
sslUsed
是否启用ssl加密,安全模式集群配置为“true”。
loadBalancerHttpPort
LoadBalance的HTTP、HTTPS端口。
登录FusionInsight Manager,选择“集群 > 服务 > ClickHouse > 逻辑集群”,查看对应逻辑集群的“HTTP Balancer端口号”中的“非加密端口”及“加密端口”。
loadBalancerHttpsPort
CLICKHOUSE_SECURITY_ENABLED
ClickHouse安全模式开关。
本示例中,配置为“true”。
user
准备好的开发用户的认证信息,如果是机机用户,“password”为空。
密码明文存储存在安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全
password
isMachineUser
认证用户是否为机机用户。
isSupportMachineUser
是否支持机机用户认证的功能,在本示例中配置为“false”。
clusterName
程序连接的ClickHouse逻辑集群名称,在本示例中保持默认值“default_cluster”。
databaseName
样例代码工程中需要创建的数据库和数据表名称,可以根据实际情况修改。
tableName
batchRows
一个批次写入数据的条数,在本示例中配置为“10”。
batchNum
写入数据的总批次,在本示例中保持默认值。
clickhouse_dataSource_ip_list
ClickHouseBalancer实例的地址和HTTP连接端口信息。
登录FusionInsight Manager,选择“集群 > 服务 > ClickHouse > 逻辑集群”,本示例为安全模式集群,因此查看对应逻辑集群的“HTTP Balancer端口号”中的“加密端口”。
例如本示例中,配置为“192.168.64.10:21426,192.168.64.122:21426”。
native_dataSource_ip_list
ClickHouseBalancer实例的地址和TCP连接端口信息。
登录FusionInsight Manager,选择“集群 > 服务 > ClickHouse > 逻辑集群”,查看对应逻辑集群的“TCP Balancer端口号”中的“非加密端口”。
例如本示例中,配置为“192.168.64.10:21424,192.168.64.122:21424”。
- 本样例工程中,基于业务场景的开发思路如下,通过clickhouse-jdbc API接口来进行实现,各功能代码片段详情说明可参考开发ClickHouse应用。
- 建立连接:建立和ClickHouse服务实例的连接。
创建连接时传入表1中配置的用户信息作为认证凭据,在服务端进行安全认证。
clickHouseProperties.setPassword(userPass); clickHouseProperties.setUser(userName); BalancedClickhouseDataSource balancedClickhouseDataSource = new BalancedClickhouseDataSource(JDBC_PREFIX + UriList, clickHouseProperties);
- 创建库:创建ClickHouse数据库。
- 创建表:创建ClickHouse数据库下的表。
通过on cluster语句在集群中创建ReplicatedMerge表和Distributed表。
private void createTable(String databaseName, String tableName, String clusterName) throws Exception { String createSql = "create table " + databaseName + "." + tableName + " on cluster " + clusterName + " (name String, age UInt8, date Date)engine=ReplicatedMergeTree('/clickhouse/tables/{shard}/" + databaseName + "." + tableName + "'," + "'{replica}') partition by toYYYYMM(date) order by age"; String createDisSql = "create table " + databaseName + "." + tableName + "_all" + " on cluster " + clusterName + " as " + databaseName + "." + tableName + " ENGINE = Distributed(default_cluster," + databaseName + "," + tableName + ", rand());"; ArrayList<String> sqlList = new ArrayList<String>(); sqlList.add(createSql); sqlList.add(createDisSql); util.exeSql(sqlList); }
- 插入数据:插入数据到ClickHouse表中。
向创建的表中插入数据,本示例创建的表具有三个字段,分别是String、UInt8和Date类型。
String insertSql = "insert into " + databaseName + "." + tableName + " values (?,?,?)"; PreparedStatement preparedStatement = connection.prepareStatement(insertSql); long allBatchBegin = System.currentTimeMillis(); for (int j = 0; j < batchNum; j++) { for (int i = 0; i < batchRows; i++) { preparedStatement.setString(1, "huawei_" + (i + j * 10)); preparedStatement.setInt(2, ((int) (Math.random() * 100))); preparedStatement.setDate(3, generateRandomDate("2018-01-01", "2021-12-31")); preparedStatement.addBatch(); } long begin = System.currentTimeMillis(); preparedStatement.executeBatch(); long end = System.currentTimeMillis(); log.info("Inert batch time is {} ms", end - begin); } long allBatchEnd = System.currentTimeMillis(); log.info("Inert all batch time is {} ms", allBatchEnd - allBatchBegin);
- 建立连接:建立和ClickHouse服务实例的连接。
编译并运行程序
本地和MRS集群网络互通时,可以直接在本地进行调测运行。
- 在开发环境IntelliJ IDEA工程“clickhouse-examples”中单击“Run 'Demo'”运行应用程序工程。
图2 运行ClickHouse Demo程序
- 控制台显示部分运行结果如下,可以看到ClickHouse表创建成功并插入数据。
... 2023-06-03 11:30:27,127 | INFO | main | Execute query:create table testdb.testtb on cluster default_cluster (name String, age UInt8, date Date)engine=ReplicatedMergeTree('/clickhouse/tables/{shard}/testdb.testtb','{replica}') partition by toYYYYMM(date) order by age | com.huawei.clickhouse.examples.Util.exeSql(Util.java:68) 2023-06-03 11:30:27,412 | INFO | main | Execute time is 284 ms | com.huawei.clickhouse.examples.Util.exeSql(Util.java:72) 2023-06-03 11:30:27,412 | INFO | main | Current load balancer is 192.168.64.10:21426 | com.huawei.clickhouse.examples.Util.exeSql(Util.java:63) 2023-06-03 11:30:28,426 | INFO | main | Execute query:create table testdb.testtb_all on cluster default_cluster as testdb.testtb ENGINE = Distributed(default_cluster,testdb,testtb, rand()); | com.huawei.clickhouse.examples.Util.exeSql(Util.java:68) 2023-06-03 11:30:28,686 | INFO | main | Execute time is 259 ms | com.huawei.clickhouse.examples.Util.exeSql(Util.java:72) 2023-06-03 11:30:28,686 | INFO | main | Current load balancer is 192.168.64.10:21426 | com.huawei.clickhouse.examples.Util.insertData(Util.java:137) 2023-06-03 11:30:29,784 | INFO | main | Insert batch time is 227 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:31,490 | INFO | main | Insert batch time is 200 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:33,337 | INFO | main | Insert batch time is 335 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:35,295 | INFO | main | Insert batch time is 454 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:37,077 | INFO | main | Insert batch time is 275 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:38,811 | INFO | main | Insert batch time is 218 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:40,468 | INFO | main | Insert batch time is 144 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:42,216 | INFO | main | Insert batch time is 238 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:43,977 | INFO | main | Insert batch time is 257 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:45,756 | INFO | main | Insert batch time is 277 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:154) 2023-06-03 11:30:47,270 | INFO | main | Inert all batch time is 17720 ms | com.huawei.clickhouse.examples.Util.insertData(Util.java:158) 2023-06-03 11:30:47,271 | INFO | main | Current load balancer is 192.168.64.10:21426 | com.huawei.clickhouse.examples.Util.exeSql(Util.java:63) 2023-06-03 11:30:47,828 | INFO | main | Execute query:select * from testdb.testtb_all order by age limit 10 | com.huawei.clickhouse.examples.Util.exeSql(Util.java:68) 2023-06-03 11:30:47,917 | INFO | main | Execute time is 89 ms | com.huawei.clickhouse.examples.Util.exeSql(Util.java:72) 2023-06-03 11:30:47,918 | INFO | main | Current load balancer is 192.168.64.10:21426 | com.huawei.clickhouse.examples.Util.exeSql(Util.java:63) 2023-06-03 11:30:48,580 | INFO | main | Execute query:select toYYYYMM(date),count(1) from testdb.testtb_all group by toYYYYMM(date) order by count(1) DESC limit 10 | com.huawei.clickhouse.examples.Util.exeSql(Util.java:68) 2023-06-03 11:30:48,680 | INFO | main | Execute time is 99 ms | com.huawei.clickhouse.examples.Util.exeSql(Util.java:72) 2023-06-03 11:30:48,682 | INFO | main | name age date | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,682 | INFO | main | huawei_89 3 2021-02-21 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,682 | INFO | main | huawei_81 3 2020-05-27 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,682 | INFO | main | huawei_70 4 2021-10-28 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,682 | INFO | main | huawei_73 4 2020-03-23 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,683 | INFO | main | huawei_44 5 2020-12-10 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,683 | INFO | main | huawei_29 6 2021-10-12 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,683 | INFO | main | huawei_74 6 2021-03-03 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,683 | INFO | main | huawei_38 7 2020-05-30 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,683 | INFO | main | huawei_57 8 2020-09-27 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,683 | INFO | main | huawei_23 8 2020-08-08 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,683 | INFO | main | toYYYYMM(date) count() | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,684 | INFO | main | 202005 8 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,684 | INFO | main | 202007 7 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,684 | INFO | main | 202004 6 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,684 | INFO | main | 202009 6 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,684 | INFO | main | 202103 6 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,685 | INFO | main | 202012 6 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,685 | INFO | main | 202010 5 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,685 | INFO | main | 202112 5 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,685 | INFO | main | 202003 5 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,685 | INFO | main | 202104 4 | com.huawei.clickhouse.examples.Demo.queryData(Demo.java:159) 2023-06-03 11:30:48,689 | INFO | main | Use HA module. | ru.yandex.clickhouse.BalancedClickhouseDataSource.<init>(BalancedClickhouseDataSource.java:122) 2023-06-03 11:30:51,651 | INFO | main | Name is: huawei_89, age is: 3 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,651 | INFO | main | Name is: huawei_81, age is: 3 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,651 | INFO | main | Name is: huawei_70, age is: 4 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,651 | INFO | main | Name is: huawei_73, age is: 4 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,652 | INFO | main | Name is: huawei_44, age is: 5 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,652 | INFO | main | Name is: huawei_29, age is: 6 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,652 | INFO | main | Name is: huawei_74, age is: 6 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,652 | INFO | main | Name is: huawei_38, age is: 7 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,654 | INFO | main | Name is: huawei_57, age is: 8 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) 2023-06-03 11:30:51,654 | INFO | main | Name is: huawei_23, age is: 8 | com.huawei.clickhouse.examples.ClickhouseJDBCHaDemo.queryData(ClickhouseJDBCHaDemo.java:73) ...
- 安装MRS集群客户端,登录ClickHouse客户端。
例如客户端安装目录为“/opt/client”,以客户端安装用户,登录安装客户端的节点。
cd /opt/client
source bigdata_env
kinit developuser
- 使用clickhouse client命令连接ClickHouse服务端:
clickhouse client --host ClickHouseServer的实例IP --port 连接端口 --secure
ClickHouse的实例IP地址可登录集群FusionInsight Manager,然后选择“集群 > 服务 > ClickHouse > 实例”,获取ClickHouseServer实例对应的业务IP地址。连接端口可通过ClickHouse服务配置中搜索“tcp_port_secure”参数获取。
例如执行命令如下:
clickhouse client --host 192.168.64.10 --port 21427 --secure
- 执行以下命令,查看程序创建的数据表内容。
select * from testdb.testtb;
┌─name──────┬─age─┬───────date─┐ │ huawei_70 │ 4 │ 2021-10-28 │ │ huawei_29 │ 6 │ 2021-10-12 │ │ huawei_16 │ 28 │ 2021-10-04 │ │ huawei_15 │ 29 │ 2021-10-03 │ └───────────┴─────┴────────────┘ ...