Spring Boot 接入华为 MRS ClickHouse(JDBC + 安全认证 + 负载均衡)实战

Spring Boot 接入华为 MRS ClickHouse(JDBC + 安全认证 + 负载均衡)实战

摘要:本文以真实落地项目为例,完整记录 Spring Boot 接入华为 MRS(FusionInsight)ClickHouse 集群的适配流程,覆盖定制 JDBC 驱动选型、外置配置设计、负载均衡器连接方式、安全认证(用户密码/机器用户)、分布式建表与批量插入等关键环节,并给出实测踩坑记录(含错误码)。方案已在 MRS 3.3.1 集群验证通过,可直接复用。


一、背景:MRS ClickHouse 与普通 ClickHouse 的差异

MRS 是华为云大数据平台,FusionInsight 是其私有化部署形态。MRS ClickHouse 虽然底层是 ClickHouse 引擎,但对外接入方式与社区版有明显差异,主要体现在三点:

  1. 统一入口是"负载均衡器"(ClickHouseBalancer),不是数据节点。业务侧连接串只指向 Balancer 的 IP,由它转发到集群内的 ClickHouseServer,因此应用无需感知分片/副本拓扑,天然具备故障转移能力;
  2. 安全集群强制认证。默认开启安全模式,JDBC 连接必须提供凭证------普通用户走「用户名 + 密码」,机器用户走 keytab 文件,与普通 ClickHouse 免密或单密码不同;
  3. 依赖必须用华为定制版clickhouse-jdbc 官方版本无法对接 MRS,需使用带 h0.cbu.mrs 后缀的定制驱动,且该驱动会传递引入与 Spring Boot 冲突的日志依赖,需要显式排除。

本文以 Spring Boot 2.7 + JDK 1.8 项目为例,给出完整可运行的接入方案。

二、连接拓扑与端口规划(先搞清连哪里)

MRS ClickHouse 的 Balancer 对外暴露多套端口,分别对应不同协议与加密方式:

协议 端口(本集群) 用途
HTTP(明文) 21426 JDBC/HTTP 非加密连接
HTTPS 21428 JDBC/HTTP 加密连接(安全模式必用)
Native TCP 21424 原生客户端非加密连接
Native TCP + TLS 21425 原生客户端加密连接

关键结论:

  • JDBC(HTTP 协议)走 21426/21428,native 客户端走 21424/21425,两者不要混用;
  • 安全模式(sslUsed=true)下,代码会自动选用 HTTPS 端口,实际使用 21428。如果连接串仍写 21426,会被 Balancer 拒绝或握手失败;
  • 以上端口为本集群实测值,具体以 FusionInsight Manager 或服务器 ss -tlnp | grep -E '2142[4-8]' 查询结果为准;
  • Balancer IP 可以配置多个(负载均衡列表),驱动侧逐个尝试,实现高可用。

三、pom.xml:华为定制 JDBC 驱动

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.0</version>
</parent>

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- ★ MRS 定制 ClickHouse JDBC 驱动 -->
    <dependency>
        <groupId>com.clickhouse</groupId>
        <artifactId>clickhouse-jdbc</artifactId>
        <version>0.4.5-h0.cbu.mrs.331.r10</version>
        <exclusions>
            <!-- ★ 排除 slf4j-api,避免与 Spring Boot 日志体系冲突 -->
            <exclusion>
                <artifactId>slf4j-api</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

两个关键点:

  1. 版本号对应 MRS 版本 :0.4.5-h0.cbu.mrs.331.r10 对应 MRS 3.3.1 配套的 ClickHouse 客户端。该制品不发布在 Maven 中央仓库,需要从 MRS 客户端配套依赖或公司 Maven 私服获取(内网地址,本文不做展开);
  2. 必须排除 slf4j-api:定制驱动内部依赖 slf4j,不排除会与 Spring Boot 默认日志实现冲突,导致日志异常或启动报错。

四、配置文件:外置 conf 的设计

这个样例最有特色的设计是:连接参数不走 application.yml,而是放在运行目录外的 conf/clickhouse-example.properties,由代码主动加载。好处是部署后改集群地址/账号无需重新打包,坏处是目录结构必须正确,否则启动后请求才报文件找不到。

conf/clickhouse-example.properties 全字段:

properties 复制代码
# Balancer(负载均衡器)IP 列表,多个用逗号分隔
loadBalancerIPList=<lb_ip_1>,<lb_ip_2>

# 是否启用 SSL(安全模式必须为 true)
sslUsed=true
# HTTP 明文端口(sslUsed=false 时生效)
loadBalancerHttpPort=21426
# HTTPS 端口(sslUsed=true 时生效,安全模式实测用 21428)
loadBalancerHttpsPort=21428

# 集群是否开启安全认证
CLICKHOUSE_SECURITY_ENABLED=true

# 普通用户认证(安全模式下使用)
user=<your_user>
password=<your_password>

# 是否机器用户认证(需 conf/user.keytab,与上面互斥)
isMachineUser=false
isSupportMachineUser=false

# 集群名/库名/表名(on cluster 分布式 DDL 使用)
clusterName=<cluster_name>
databaseName=<database>
tableName=<table>
# 批量插入参数:batchNum 批 × batchRows 行
batchRows=10000
batchNum=10

application.yml 只需要服务端口等无关 Redis/数据库的参数:

yaml 复制代码
spring:
  main:
    allow-bean-definition-overriding: true
server:
  port: 8084

字段选型逻辑值得注意(代码中 getProperties() 的规则):

  • sslUsed=true 时,代码读取 loadBalancerHttpsPort(21428) ;sslUsed=false 才读明文端口;
  • CLICKHOUSE_SECURITY_ENABLED=true 时才会读取 password,非安全集群可留空;
  • isMachineUser=true 时走 keytab 认证(需把 user.keytab 放到 conf/ 目录),与用户名密码互斥。

五、核心代码解析

5.1 整体调用链

复制代码
ClickHouseExampleController (/clickhouse/executeQuery)
        ↓
ClickHouseExampleService
        ↓
ClickHouseFunc       # 流程编排:读配置 → 组装 LB 列表 → drop → 建库 → 建表 → 插数 → 查询
        ↓
Util                 # JDBC 执行层:建连、多 Balancer 容错重试、批量插入、结果解析

Controller、Service 均为标准 Spring 三层写法,真正的技术含量在 ClickHouseFunc(流程编排)与 Util(JDBC 执行)中。

5.2 JDBC 连接:安全 + SSL 参数

java 复制代码
private static final String JDBC_PREFIX = "jdbc:clickhouse://";

static Properties clickHouseProperties = new Properties();

private static void initProperties(Properties props) {
    String user = ClickHouseFunc.user;
    String password = ClickHouseFunc.password == null ? "" : ClickHouseFunc.password;
    try {
        Class.forName("com.clickhouse.jdbc.ClickHouseDriver");
    } catch (Exception e) {
        log.error(e.getMessage());
    }
    props.setProperty(ClickHouseClientOption.CONNECTION_TIMEOUT.getKey(), "60000");
    props.setProperty(ClickHouseClientOption.SOCKET_TIMEOUT.getKey(), "300000");
    props.setProperty(ClickHouseClientOption.MAX_EXECUTION_TIME.getKey(), "0"); // 查询不限时
    props.setProperty("user", user);
    props.setProperty("password", password);
    // 机器用户模式:额外指定 keytab(conf/user.keytab)
    if (ClickHouseFunc.isSec && ClickHouseFunc.isMachineUser) {
        props.setProperty("isMachineUser", "true");
        props.setProperty("keytabPath", System.getProperty("user.dir") + File.separator + "conf" + File.separator + "user.keytab");
    }
    // SSL:安全模式必须开启,并关闭证书校验(内网自签证书)
    if (ClickHouseFunc.sslUsed) {
        props.setProperty(ClickHouseClientOption.SSL.getKey(), "true");
        props.setProperty(ClickHouseClientOption.SSL_MODE.getKey(), "none");
    }
}

连接时 URL 指向 Balancer (不是数据节点),实际建连串形如 jdbc:clickhouse://<ip>:21428,驱动内部会解析为 https://<ip>:21428/default(日志中可见):

java 复制代码
ClickHouseDataSource dataSource =
        new ClickHouseDataSource(JDBC_PREFIX + server, clickHouseProperties);
try (Connection conn = dataSource.getConnection(user, password);
     PreparedStatement stmt = conn.prepareStatement(sql)) {
    ResultSet rs = stmt.executeQuery();
    // 解析结果...
}

5.3 多 Balancer 容错:轮询 + 指数退避

这是样例工程里最值得借鉴的部分------配置了多个 Balancer IP 时,依次尝试,失败后指数退避重试下一台,全部失败才抛异常:

java 复制代码
public static List<List<String>> executeQuery(String sql) throws Exception {
    List<String> serverList = ClickHouseFunc.ckLbServerList; // 形如 [ip:port, ip:port]
    initProperties(clickHouseProperties);
    int tries = 0;
    StringBuilder errorDetails = new StringBuilder();
    while (tries < serverList.size()) {
        String server = serverList.get(tries);
        boolean ok = execSqlOnServer(sql, server, resultList, errorDetails);
        if (ok) break;
        tries++;
        if (tries < serverList.size()) {
            long backoffMs = 1000L * (long) Math.pow(2, tries - 1); // 1s、2s、4s...
            Thread.sleep(backoffMs);
        }
        if (tries == serverList.size()) {
            throw new SQLException("Failed on all servers. Details: " + errorDetails);
        }
    }
    return resultList;
}

5.4 集群分布式 DDL 与数据写入

MRS ClickHouse 的分布式表通常成对出现:本地表(ReplicatedMergeTree)+ 分布式表(Distributed)。样例的建表 SQL 模板:

sql 复制代码
-- 建库(on cluster 全集群生效)
create database if not exists <database> on cluster <cluster_name>;

-- 本地表:ReplicatedMergeTree,{shard}/{replica} 由集群自动填充
create table if not exists <database>.<table> on cluster <cluster_name>
(name String, age UInt8, date Date)
engine = ReplicatedMergeTree('/clickhouse/tables/{shard}/<database>.<table>', '{replica}')
partition by toYYYYMM(date) order by age;

-- 分布式表(查询入口):rand() 随机分布到各分片
create table if not exists <database>.<table>_all on cluster <cluster_name>
(name String, age UInt8, date Date)
ENGINE = Distributed(<cluster_name>, <database>, <table>, rand());

批量插入用标准 PreparedStatement + 分批 executeBatch,样例参数为 batchNum × batchRows(10 × 10000 行),每批之间 sleep(1500) 防止打满服务端:

java 复制代码
String insertSql = "insert into " + databaseName + "." + tableName + " values (?,?,?)";
for (int j = 0; j < batchNum; j++) {
    for (int i = 0; i < batchRows; i++) {
        statement.setString(1, "huawei_" + (i + j * 10));
        statement.setInt(2, (int) (Math.random() * 100));
        statement.setDate(3, randomDate);
        statement.addBatch();
    }
    statement.executeBatch();   // 每批一次网络往返
    Thread.sleep(1500);
}

⚠️ 注意:官方样例的 executeQuery() 是"全流程演示",每次调用都会 drop 旧表再重建(为了演示幂等)。业务项目接入时务必去掉 drop/create 步骤,只保留建连 + insert/select。

六、运行与验证

6.1 运行

两种方式任选:

  • IDE 直接运行 ClickHouseApplication(注意工作目录下要有 conf/clickhouse-example.properties);
  • 打包运行 :mvn package(工程已配置 maven-assembly-plugin 打出 jar-with-dependencies),把 conf/ 目录放在与 jar 同级的运行目录下再 java -jar

6.2 验证

bash 复制代码
curl http://localhost:8084/clickhouse/executeQuery

返回 ClickHouse springboot client runs normally. 即全部链路打通。日志(clickhouse-springboot-example.log)中会依次出现关键里程碑:

复制代码
loadBalancerIPList is ..., loadBalancerHttpPort is 21428 ...   ← 配置加载成功(注意是 HTTPS 端口)
Try times is 0, current load balancer is <ip>:21428.           ← 正在连接 Balancer
Execute sql create database if not exists ... on cluster ..., time is ... ms
Insert batch time is ... ms                                    ← 批量插入

之后即可查询到 name/age/date 的演示数据。

七、常见问题(实测错误码)

报错(含错误码) 根因 解法
Code: 497. Not enough privileges ... grant CLUSTER ON *.* 用户无集群级权限,on cluster 分布式 DDL 被拒 FusionInsight Manager 中给用户授予 CLUSTER 相关权限后重试(本项目实测遇到)
Code: 701. Requested cluster 'default_cluster' not found clusterName 配错(如误写默认值 default_cluster) 改为 Manager 中集群的真实名称(本项目实测遇到)
连接被拒 / SSL 握手失败 sslUsed=true 却连了明文 HTTP 端口 21426 确认使用 HTTPS 端口 21428;sslUsed=false 才用 21426
FileNotFoundException: conf/clickhouse-example.properties 运行目录下缺少 conf/ 目录或文件 保证运行目录结构与 conf/clickhouse-example.properties 一致(与 jar 同级)
日志/类加载异常 定制驱动传递引入 slf4j 与 Spring Boot 冲突 pom 中排除 slf4j-api(见第三节)
SSLHandshakeException 内网自签证书校验失败 驱动设置 ssl_mode=none(仅限内网/测试环境,生产建议导入 CA 证书)
所有 Balancer 都失败后报 SQLException: Failed to exec the sql on all n servers 每个 LB 都被尝试且失败(原因见 errorDetails) 查看日志中 errorDetails 的具体错误码,多为权限或端口问题

八、总结

MRS ClickHouse 接入的三个要点:

  1. 连对入口与端口:统一连 Balancer 而非数据节点;安全模式走 HTTPS 端口(本项目为 21428),协议(JDBC HTTP vs Native)与端口一一对应;
  2. 认证与依赖配套 :安全集群需用户名密码(或机器用户 keytab);驱动必须用 h0.cbu.mrs 定制版并排除 slf4j-api;
  3. 分布式语义 :建库建表都要带 on cluster <真实集群名>,读写入口是 Distributed 分布式表,clusterName 配错会直接报 Code 701。

本文方案整理自已在 MRS 3.3.1 集群验证通过的示例项目(含两次真实权限/集群名踩坑),希望能帮你快速打通 MRS ClickHouse 这条接入链路。

Spring Boot 接入华为 MRS ClickHouse(JDBC + 安全认证 + 负载均衡)实战

摘要:本文以真实落地项目为例,完整记录 Spring Boot 接入华为 MRS(FusionInsight)ClickHouse 集群的适配流程,覆盖定制 JDBC 驱动选型、外置配置设计、负载均衡器连接方式、安全认证(用户密码/机器用户)、分布式建表与批量插入等关键环节,并给出实测踩坑记录(含错误码)。方案已在 MRS 3.3.1 集群验证通过,可直接复用。


一、背景:MRS ClickHouse 与普通 ClickHouse 的差异

MRS 是华为云大数据平台,FusionInsight 是其私有化部署形态。MRS ClickHouse 虽然底层是 ClickHouse 引擎,但对外接入方式与社区版有明显差异,主要体现在三点:

  1. 统一入口是"负载均衡器"(ClickHouseBalancer),不是数据节点。业务侧连接串只指向 Balancer 的 IP,由它转发到集群内的 ClickHouseServer,因此应用无需感知分片/副本拓扑,天然具备故障转移能力;
  2. 安全集群强制认证。默认开启安全模式,JDBC 连接必须提供凭证------普通用户走「用户名 + 密码」,机器用户走 keytab 文件,与普通 ClickHouse 免密或单密码不同;
  3. 依赖必须用华为定制版clickhouse-jdbc 官方版本无法对接 MRS,需使用带 h0.cbu.mrs 后缀的定制驱动,且该驱动会传递引入与 Spring Boot 冲突的日志依赖,需要显式排除。

本文以 Spring Boot 2.7 + JDK 1.8 项目为例,给出完整可运行的接入方案。

二、连接拓扑与端口规划(先搞清连哪里)

MRS ClickHouse 的 Balancer 对外暴露多套端口,分别对应不同协议与加密方式:

协议 端口(本集群) 用途
HTTP(明文) 21426 JDBC/HTTP 非加密连接
HTTPS 21428 JDBC/HTTP 加密连接(安全模式必用)
Native TCP 21424 原生客户端非加密连接
Native TCP + TLS 21425 原生客户端加密连接

关键结论:

  • JDBC(HTTP 协议)走 21426/21428,native 客户端走 21424/21425,两者不要混用;
  • 安全模式(sslUsed=true)下,代码会自动选用 HTTPS 端口,实际使用 21428。如果连接串仍写 21426,会被 Balancer 拒绝或握手失败;
  • 以上端口为本集群实测值,具体以 FusionInsight Manager 或服务器 ss -tlnp | grep -E '2142[4-8]' 查询结果为准;
  • Balancer IP 可以配置多个(负载均衡列表),驱动侧逐个尝试,实现高可用。

三、pom.xml:华为定制 JDBC 驱动

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.0</version>
</parent>

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- ★ MRS 定制 ClickHouse JDBC 驱动 -->
    <dependency>
        <groupId>com.clickhouse</groupId>
        <artifactId>clickhouse-jdbc</artifactId>
        <version>0.4.5-h0.cbu.mrs.331.r10</version>
        <exclusions>
            <!-- ★ 排除 slf4j-api,避免与 Spring Boot 日志体系冲突 -->
            <exclusion>
                <artifactId>slf4j-api</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

两个关键点:

  1. 版本号对应 MRS 版本 :0.4.5-h0.cbu.mrs.331.r10 对应 MRS 3.3.1 配套的 ClickHouse 客户端。该制品不发布在 Maven 中央仓库,需要从 MRS 客户端配套依赖或公司 Maven 私服获取(内网地址,本文不做展开);
  2. 必须排除 slf4j-api:定制驱动内部依赖 slf4j,不排除会与 Spring Boot 默认日志实现冲突,导致日志异常或启动报错。

四、配置文件:外置 conf 的设计

这个样例最有特色的设计是:连接参数不走 application.yml,而是放在运行目录外的 conf/clickhouse-example.properties,由代码主动加载。好处是部署后改集群地址/账号无需重新打包,坏处是目录结构必须正确,否则启动后请求才报文件找不到。

conf/clickhouse-example.properties 全字段:

properties 复制代码
# Balancer(负载均衡器)IP 列表,多个用逗号分隔
loadBalancerIPList=<lb_ip_1>,<lb_ip_2>

# 是否启用 SSL(安全模式必须为 true)
sslUsed=true
# HTTP 明文端口(sslUsed=false 时生效)
loadBalancerHttpPort=21426
# HTTPS 端口(sslUsed=true 时生效,安全模式实测用 21428)
loadBalancerHttpsPort=21428

# 集群是否开启安全认证
CLICKHOUSE_SECURITY_ENABLED=true

# 普通用户认证(安全模式下使用)
user=<your_user>
password=<your_password>

# 是否机器用户认证(需 conf/user.keytab,与上面互斥)
isMachineUser=false
isSupportMachineUser=false

# 集群名/库名/表名(on cluster 分布式 DDL 使用)
clusterName=<cluster_name>
databaseName=<database>
tableName=<table>
# 批量插入参数:batchNum 批 × batchRows 行
batchRows=10000
batchNum=10

application.yml 只需要服务端口等无关 Redis/数据库的参数:

yaml 复制代码
spring:
  main:
    allow-bean-definition-overriding: true
server:
  port: 8084

字段选型逻辑值得注意(代码中 getProperties() 的规则):

  • sslUsed=true 时,代码读取 loadBalancerHttpsPort(21428) ;sslUsed=false 才读明文端口;
  • CLICKHOUSE_SECURITY_ENABLED=true 时才会读取 password,非安全集群可留空;
  • isMachineUser=true 时走 keytab 认证(需把 user.keytab 放到 conf/ 目录),与用户名密码互斥。

五、核心代码解析

5.1 整体调用链

复制代码
ClickHouseExampleController (/clickhouse/executeQuery)
        ↓
ClickHouseExampleService
        ↓
ClickHouseFunc       # 流程编排:读配置 → 组装 LB 列表 → drop → 建库 → 建表 → 插数 → 查询
        ↓
Util                 # JDBC 执行层:建连、多 Balancer 容错重试、批量插入、结果解析

Controller、Service 均为标准 Spring 三层写法,真正的技术含量在 ClickHouseFunc(流程编排)与 Util(JDBC 执行)中。

5.2 JDBC 连接:安全 + SSL 参数

java 复制代码
private static final String JDBC_PREFIX = "jdbc:clickhouse://";

static Properties clickHouseProperties = new Properties();

private static void initProperties(Properties props) {
    String user = ClickHouseFunc.user;
    String password = ClickHouseFunc.password == null ? "" : ClickHouseFunc.password;
    try {
        Class.forName("com.clickhouse.jdbc.ClickHouseDriver");
    } catch (Exception e) {
        log.error(e.getMessage());
    }
    props.setProperty(ClickHouseClientOption.CONNECTION_TIMEOUT.getKey(), "60000");
    props.setProperty(ClickHouseClientOption.SOCKET_TIMEOUT.getKey(), "300000");
    props.setProperty(ClickHouseClientOption.MAX_EXECUTION_TIME.getKey(), "0"); // 查询不限时
    props.setProperty("user", user);
    props.setProperty("password", password);
    // 机器用户模式:额外指定 keytab(conf/user.keytab)
    if (ClickHouseFunc.isSec && ClickHouseFunc.isMachineUser) {
        props.setProperty("isMachineUser", "true");
        props.setProperty("keytabPath", System.getProperty("user.dir") + File.separator + "conf" + File.separator + "user.keytab");
    }
    // SSL:安全模式必须开启,并关闭证书校验(内网自签证书)
    if (ClickHouseFunc.sslUsed) {
        props.setProperty(ClickHouseClientOption.SSL.getKey(), "true");
        props.setProperty(ClickHouseClientOption.SSL_MODE.getKey(), "none");
    }
}

连接时 URL 指向 Balancer (不是数据节点),实际建连串形如 jdbc:clickhouse://<ip>:21428,驱动内部会解析为 https://<ip>:21428/default(日志中可见):

java 复制代码
ClickHouseDataSource dataSource =
        new ClickHouseDataSource(JDBC_PREFIX + server, clickHouseProperties);
try (Connection conn = dataSource.getConnection(user, password);
     PreparedStatement stmt = conn.prepareStatement(sql)) {
    ResultSet rs = stmt.executeQuery();
    // 解析结果...
}

5.3 多 Balancer 容错:轮询 + 指数退避

这是样例工程里最值得借鉴的部分------配置了多个 Balancer IP 时,依次尝试,失败后指数退避重试下一台,全部失败才抛异常:

java 复制代码
public static List<List<String>> executeQuery(String sql) throws Exception {
    List<String> serverList = ClickHouseFunc.ckLbServerList; // 形如 [ip:port, ip:port]
    initProperties(clickHouseProperties);
    int tries = 0;
    StringBuilder errorDetails = new StringBuilder();
    while (tries < serverList.size()) {
        String server = serverList.get(tries);
        boolean ok = execSqlOnServer(sql, server, resultList, errorDetails);
        if (ok) break;
        tries++;
        if (tries < serverList.size()) {
            long backoffMs = 1000L * (long) Math.pow(2, tries - 1); // 1s、2s、4s...
            Thread.sleep(backoffMs);
        }
        if (tries == serverList.size()) {
            throw new SQLException("Failed on all servers. Details: " + errorDetails);
        }
    }
    return resultList;
}

5.4 集群分布式 DDL 与数据写入

MRS ClickHouse 的分布式表通常成对出现:本地表(ReplicatedMergeTree)+ 分布式表(Distributed)。样例的建表 SQL 模板:

sql 复制代码
-- 建库(on cluster 全集群生效)
create database if not exists <database> on cluster <cluster_name>;

-- 本地表:ReplicatedMergeTree,{shard}/{replica} 由集群自动填充
create table if not exists <database>.<table> on cluster <cluster_name>
(name String, age UInt8, date Date)
engine = ReplicatedMergeTree('/clickhouse/tables/{shard}/<database>.<table>', '{replica}')
partition by toYYYYMM(date) order by age;

-- 分布式表(查询入口):rand() 随机分布到各分片
create table if not exists <database>.<table>_all on cluster <cluster_name>
(name String, age UInt8, date Date)
ENGINE = Distributed(<cluster_name>, <database>, <table>, rand());

批量插入用标准 PreparedStatement + 分批 executeBatch,样例参数为 batchNum × batchRows(10 × 10000 行),每批之间 sleep(1500) 防止打满服务端:

java 复制代码
String insertSql = "insert into " + databaseName + "." + tableName + " values (?,?,?)";
for (int j = 0; j < batchNum; j++) {
    for (int i = 0; i < batchRows; i++) {
        statement.setString(1, "huawei_" + (i + j * 10));
        statement.setInt(2, (int) (Math.random() * 100));
        statement.setDate(3, randomDate);
        statement.addBatch();
    }
    statement.executeBatch();   // 每批一次网络往返
    Thread.sleep(1500);
}

⚠️ 注意:官方样例的 executeQuery() 是"全流程演示",每次调用都会 drop 旧表再重建(为了演示幂等)。业务项目接入时务必去掉 drop/create 步骤,只保留建连 + insert/select。

六、运行与验证

6.1 运行

两种方式任选:

  • IDE 直接运行 ClickHouseApplication(注意工作目录下要有 conf/clickhouse-example.properties);
  • 打包运行 :mvn package(工程已配置 maven-assembly-plugin 打出 jar-with-dependencies),把 conf/ 目录放在与 jar 同级的运行目录下再 java -jar

6.2 验证

bash 复制代码
curl http://localhost:8084/clickhouse/executeQuery

返回 ClickHouse springboot client runs normally. 即全部链路打通。日志(clickhouse-springboot-example.log)中会依次出现关键里程碑:

复制代码
loadBalancerIPList is ..., loadBalancerHttpPort is 21428 ...   ← 配置加载成功(注意是 HTTPS 端口)
Try times is 0, current load balancer is <ip>:21428.           ← 正在连接 Balancer
Execute sql create database if not exists ... on cluster ..., time is ... ms
Insert batch time is ... ms                                    ← 批量插入

之后即可查询到 name/age/date 的演示数据。

七、常见问题(实测错误码)

报错(含错误码) 根因 解法
Code: 497. Not enough privileges ... grant CLUSTER ON *.* 用户无集群级权限,on cluster 分布式 DDL 被拒 FusionInsight Manager 中给用户授予 CLUSTER 相关权限后重试(本项目实测遇到)
Code: 701. Requested cluster 'default_cluster' not found clusterName 配错(如误写默认值 default_cluster) 改为 Manager 中集群的真实名称(本项目实测遇到)
连接被拒 / SSL 握手失败 sslUsed=true 却连了明文 HTTP 端口 21426 确认使用 HTTPS 端口 21428;sslUsed=false 才用 21426
FileNotFoundException: conf/clickhouse-example.properties 运行目录下缺少 conf/ 目录或文件 保证运行目录结构与 conf/clickhouse-example.properties 一致(与 jar 同级)
日志/类加载异常 定制驱动传递引入 slf4j 与 Spring Boot 冲突 pom 中排除 slf4j-api(见第三节)
SSLHandshakeException 内网自签证书校验失败 驱动设置 ssl_mode=none(仅限内网/测试环境,生产建议导入 CA 证书)
所有 Balancer 都失败后报 SQLException: Failed to exec the sql on all n servers 每个 LB 都被尝试且失败(原因见 errorDetails) 查看日志中 errorDetails 的具体错误码,多为权限或端口问题

八、总结

MRS ClickHouse 接入的三个要点:

  1. 连对入口与端口:统一连 Balancer 而非数据节点;安全模式走 HTTPS 端口(本项目为 21428),协议(JDBC HTTP vs Native)与端口一一对应;
  2. 认证与依赖配套 :安全集群需用户名密码(或机器用户 keytab);驱动必须用 h0.cbu.mrs 定制版并排除 slf4j-api;
  3. 分布式语义 :建库建表都要带 on cluster <真实集群名>,读写入口是 Distributed 分布式表,clusterName 配错会直接报 Code 701。

本文方案整理自已在 MRS 3.3.1 集群验证通过的示例项目(含两次真实权限/集群名踩坑),希望能帮你快速打通 MRS ClickHouse 这条接入链路。

相关推荐
摇滚侠10 小时前
《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 使用 JdbcTemplate 阅读笔记 32
spring boot·笔记·后端
思录Echo14 小时前
自助易AI数字人外挂技术剖析|如何解决政企智能客服的多端适配难题?
人工智能·华为·harmonyos
努力努力再努力wz14 小时前
【Redis入门系列】从 KEYS 到 SCAN:渐进式遍历、Cursor 与位反转原理
数据库·redis·缓存
互联网叫兽15 小时前
redis深入学习一
redis
沐沐师17 小时前
Redis 入门教程
redis·nestjs
卓怡学长17 小时前
w210基于springboot反诈平台设计与实现
java·spring boot·spring·intellij-idea
大模型丫丫19 小时前
如何提升单体 Spring Boot 应用的并发数?
java·spring boot·后端
RuoyiOffice19 小时前
SpringBoot3+Vue3 最推荐的开源 OA 系统 2026:流程驱动、资源闭环、多端互通
spring boot·vue3·flowable·oa·协同办公·spring boot 3·开源oa
吃饱了得干活19 小时前
Redis 从单机到集群:持久化、主从复制、哨兵与集群完全指南
redis·后端