使用ClickHouse JDBC官方驱动,踩坑无数

news2024/12/23 4:39:59

前言

最近遇到一个ClickHouse的线上问题:
Code: 242, e.displayText() = DB::Exception: Table is in readonly mode(zookeeper path:/clickhouse/tables/02/xxx) (version 21.12.4.1) (official build)

这个问题我在网上查原因说是由于Zookeeper压力过大,表变成只读状态,导致ClickHouse插入数据失败。

具体原因有两个:

  1. 写入数据频率过高。
  2. Zookeeper中的集群节点挂掉。

而我们项目出现这个问题的原因是第一个:写入数据频率过高。

但是在网上搜资料的过程中,我又发现了另外一个问题:我们项目用了JDBC驱动Maven groupId ru.yandex.clickhouse,但ClickHouse官方并不推荐。

于是我果断的访问了ClickHouse的官网,通过它访问了ClickHouse的GitHub地址:https://github.com/ClickHouse/clickhouse-jdbc

证实了官网确实不建议使用ru.yandex.clickhouse驱动:

而应该改成com.clickhouse驱动,并且推荐使用0.3.2以上的版本:

于是,后面几天开始了ClickHouseJDBC驱动升级之旅。踩了不少坑,拿出来跟大家一起分享一下,希望对你会有所帮助。

1. 第一次升级

ClickHouse官方GitHub上面推荐使用的JDBC驱动是0.3.2以上的版本:

于是,我果断把项目中的pom.xml文件中的groupId换成了com.clickhouse,版本换成了0.3.2

刷新了一下maven,本地启动项目,能够正常运行。

然后在本地测试了一下业务功能,能够正常从ClickHouse中读取和写入数据。

心里不禁在想:这次升级实在太容易了。

2. 第二次升级

后来,项目组的同事建议换成最新版本,说有更多新功能,并且性能有很大提升。

我听到性能有很大提升这几个字,就决定再升级试试。

于是,把版本升级成了0.3.2-patch11

在本地再次测试,业务功能一切正常。

然后把项目部署到测试环境了。

3. 发现问题了

第二天收到了两封sentry的报警邮件,报警级别都是warn

第一封邮件中提示异常:This driver is DEPRECATED. Please use [com.clickhouse.jdbc.ClickHouseDriver] instead

意思是说ru.yandex.clickhouse的驱动已经被废弃了,请使用com.clickhouse.jdbc.ClickHouseDriver驱动。

第二封邮件中提示异常:Also everything in package [ru.yandex.clickhouse] will be removed starting from 0.4.0

意思是说ru.yandex.clickhouse将被移除。

看到这两封邮件,我当时有点懵,不就是用的com.clickhouse驱动包吗,ru.yandex.clickhouse是从哪里来的?

于是全局搜索了一下ru.yandex.clickhouse关键字,并没有搜到任何记录。

这让我更懵了。

接下来,我打开了clickhouse-jdbc-0.3.2-patch11-all.jar文件,看到了让人意想不到的结果:

这个jar包下面竟然有两个目录:com.clickhouseru.yandex.clickhouse,也就是说jar包中新驱动和老驱动两种都支持。

而且ClickhouseDriver类有两个:

我此时心里有十万个为什么:为什么不直接把ru.yandex.clickhouse包的代码删除了,却在日志文件中打印一些警告呢?

这实在太坑了吧。

也就是说升级驱动之后,项目依然用的老驱动的代码,我测试了个寂寞。。。

4. 如何使用新驱动?

接下来我内心的OS是:既然ClickHouse官方驱动包,新老驱动都支持,必然有个开关控制是使用新的JDBC驱动,还是使用老的JDBC驱动。

从目前来看,如果没有调整开关,ClickHouse官方驱动包默认使用的是老的JDBC驱动。

接下来,最重要的问题是要搞清楚:如何使用新驱动?

很快,我查到通过配置下面的参数:

spring.datasource.clickhouse.drive-class-name=com.clickhouse.jdbc.ClickHouseDriver

就能指定Spring使用的JDBC驱动。

果然在application.properties文件中,配置数据源的地方,增加了这样一个配置,重启项目,Spring就是使用了新的ClickHouse JDBC驱动。

日志中没有打印邮件中那两个warn了。

此时,心里暗自窃喜,终于使用了ClickHouse官方推荐的JDBC驱动。

项目已经正常运行起来了,赶紧测试一下业务功能是否正常。

5. 出现了两个新问题

结果马上被啪啪打脸了。

在测试批量insert数据的业务场景时,系统运行日志中出现了两个异常:

异常1:
Code: 6. DB:Exception: Cannot prse string '2022-11-22 14:42:37.025' as DateTime:syntax error at position 19...
从提示的信息看,它表示时间2022-11-22 14:42:37.025不能转换成DateTime类型。

异常2:
Please consider to use one and only one values expression, for example: use 'values(?)' instead of 'values(?),(?).'从提示的信息看,它表示不支持批量insert数据。

我去。。。

升级ClickHouse JDBC驱动出问题了。

ClickHouse 官方最新的JDBC驱动竟然不支持批量insert数据,这个问题更严重。

赶紧搜索一下解决办法。

6. 回退版本

很快,在clickhouse-jdbc的issues中查到了类似的问题,地址:https://github.com/ClickHouse/clickhouse-jdbc/issues/1106
问题如下:

下面有人回答:

使用老版本就没有这个警告。

我一下子如梦初醒。

不要迷恋最新的版本,clickhouse-jdbc一定要找最合适的版本。

于是,我查了dev、st和ga环境的ClickHouse服务器版本,发现dev用的是20.12.8.5,而st和ga用的21.12.4.1

为了兼容dev环境,ClickHouse服务器版本以20+为准,再看看clickhouse-jdbc能用什么版本。

很快在releases中查到,clickhouse-jdbc能用0.3.2,最高只能0.3.2-patch1。因为0.3.2-patch2以上,要求ClickHouse服务器是21+的版本。

因此,我只能将clickhouse-jdbc的版本回退到:0.3.2-patch1

果然,回退版本之后,不能批量insert的问题解决了。

接下来,就是一个问题。

7. DateTime

让我们一起回顾一下那个问题:
Code: 6. DB:Exception: Cannot prse string '2022-11-22 14:42:37.025' as DateTime:syntax error at position 19...
从提示的信息看,它表示时间2022-11-22 14:42:37.025不能转换成DateTime类型。

而DateTime的时间格式是:yyyy-MM-dd HH:mm:ss,这个问题是由于2022-11-22 14:42:37.025包含了毫秒,不能直接转换成2022-11-22 14:42:37导致的。

我查了一下代码和表结构,代码中Entity中time字段定义成的Date类型。

而表中定义的time字段是DateTime类型。

ClickHouse官方驱动无法将Date类型的时间直接转换成DateTime类型。

怎么解决这个问题呢?

答:修改表中的字段类型不就行了,将DateTime转换成DateTime64DateTime64是支持毫秒的。

我亲测过,使用DateTime64类型接收Java中Date类型的时间,能够正常解析。

那张表有三个DateTime类型的字段:create_time、edit_time和time。

前面两个字段的字段类型,很容易就修改成功了。

但修改time字段时,却报了一个异常:
Code: 524,e.displayText() = DB::Exception: Alter of key column time from type DateTime to type DateTime64(3) must be metadata-only (20.12.8.5)

提示作为key的字段不能被修改。

这又是为什么?

8. order by

我这一次直接查看了那张表的建表语句:

show create table test;

发现该表处理主键和普通索引之外,还特别加了order by的索引。

例如:order by (code, time)

看到这里我迅速明白了,原来time字段是order by的索引字段,难怪不允许随便修改的。

于是,找DBA商讨对策。

DBA说要修改ClickHouse中表的索引字段的类型,只能重新建表,然后把数据同步过去。

很显然这个方案太麻烦了。

我在想有没有其他更简单的方案呢?

9. date_time_input_format参数

我此时在思考,不就是时间转换出的问题吗?

让ClickHouse在保存数据时,自动转换一个时间格式不就解决问题了吗?

我在网上查到一个叫:date_time_input_format的参数。

该参数允许选择日期和时间的文本表示的解析器。

它可能的值:

  • ‘best_effort’ — Enables extended parsing.

ClickHouse可以解析基本 YYYY-MM-DD HH:MM:SS 格式和所有 ISO 8601 日期和时间格式。 例如, ‘2018-06-08T01:02:03.000Z’.

  • ‘basic’ — Use basic parser.

ClickHouse只能解析基本的 YYYY-MM-DD HH:MM:SS 格式。 例如, ‘2019-08-20 10:18:56’.

默认值: ‘basic’.

原来这个是时间转换失败的根源,如果我们把date_time_input_format的值设置成best_effort,不就解决问题了。

为了不影响全局,我想只给那三张表调整date_time_input_format的值。

但是在保存设置时,报错了。

原来date_time_input_format参数只允许在MergeTree存储引擎上使用,而我们表的存储引擎用的ReplacingMergeTree

晕死了。。。

只能想想其他办法了。

10. parseDateTimeBestEffortOrNull

在insert数据的地方,用函数手动转换一下不就OK了吗?

当然修改Java的Entity中的Date类型,改成String也是可以的,不过review了一下代码,这种改动有点大,涉及的地方很多。

最小的改动是在mapper层处理,因为一个mapper中最多只有一个insert存在。

而我review了所有的ClickHouse表,只有3张表用了DateTime类型,其他的表都是DateTime64类型。

刚开始,我在ClickHouse的官方文档中查到了formatDateTime函数,测试之后发现该函数不太合适。

后来找到了parseDateTimeBestEffort系列函数,决定使用parseDateTimeBestEffortOrNull函数。

只需在mapper.xml的insert语句中,使用parseDateTimeBestEffortOrNull(#{item.time})改造一下即可。

测试后发现,时间转换问题被解决了。

后来,在select语句中又出现了这个异常。

我刚开始以为是toDate(time)函数导致的,但后面发现该select的where条件中使用了time字段作为查询条件,才导致了该问题的发生。

这时同样使用parseDateTimeBestEffortOrNull函数,解决了问题。

至此,ClickHouse的JDBC驱动包升级完成,没有再出现其他的问题。

需要特别注意的是:以后新创建的表或新加的字段,如果有时间类型的字段,务必要定义成DateTime64类型的。

其实,我们在使用ClickHouse的过程中,同样也遇到过很多坑,文章开头的那个问题只是其中一个,后面会有一篇专题文章分享给大家,敬请期待。

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力。
求一键三连:点赞、转发、在看。
关注公众号:【苏三说技术】,在公众号中回复:面试、代码神器、开发手册、时间管理有超赞的粉丝福利,另外回复:加群,可以跟很多BAT大厂的前辈交流和学习。

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

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

相关文章

MySQL基础篇之多表查询(内连接、外连接、自连接、子查询、union)

05、多表查询 5.1、多表关系 1、概述 项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分…

maven学完总结!少走弯路一百遍

一、学习方式 学完maven大概花了两天的时间,其实之前学javaweb时用的是maven,因此有点接触,一到两天便能学完maven。 这次我也做了每个知识点的流程图。 但是我学完之后我发现可能没什么要做流程图的,因为更多的是自己动手操作的…

澳大利亚昆士兰大学博士后职位—生物活性肽

【国外博士后招聘-知识人网】澳大利亚昆士兰大学博士后职位—生物活性肽 昆士兰大学(The University of Queensland),简称“昆大”“UQ” ,世界高等科研学府。始建于1910年,是昆士兰州第一所综合型大学,同时…

网页JS自动化脚本(二)查找定位页面元素的方法

我们写脚本往往是要提取某些关键字,那么我们对于元素的查找和定位就很重要首先我们打开浏览器,鼠标右键点击我们想要定位的元素,然后点击审查元素 然后浏览器会弹出调试工具台,我们继续看下图右侧的调试工具台 可以看到我画了9个序号,可以看到从第1个到第7个全部是div容器元素,…

[附源码]Python计算机毕业设计Django+Vue的健身房会员系统的设计与实现

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

数字信号处理-11-FPGA FFT IP应用实例

前言 本文根据FFT相关原理进行设计构建工程,仿造前文的工程构建的混频功能的工程,设计工程显示该混频信号的功率谱,然后进行仿真分析。 FFT仿真与分析 本文不再针对FFT的原理进行过多赘述,提供一份简单的matlab仿真代码。根据仿…

在Soliworks中便捷添加自己的LOGO

在Soliworks中,一般采用草图图片样条曲线的方式绘制个人logo,但是对于一些复杂的logo,对每个模型都绘制一遍显然是不显示的,所以我摸索了一套只需绘制LOGO一遍,就能够将其应用在其他模型的方式。 1. 绘制LOGO 采用草…

黑马点评--好友关注

好友关注: 关注和取关 在探店图文的详情页面中,可以关注发布笔记的作者: 需求:基于该数据结构,实现两个接口 关注和取关接口 Overridepublic Result follow(Long id, Boolean isFollow) {// 1.获取登录用户Long us…

软件设计师教程(二)计算机系统知识-计算机体系结构

软件设计师教程 软件设计师教程(一)计算机系统知识-计算机系统基础知识 计算机体系结构软件设计师教程计算机体系结构的发展计算机系统结构概述计算机体系结构分类指令系统指令集体系结构的分类CISC和RISC指令的流水处理阵列处理机、并行处理机和多处理…

wy的leetcode刷题记录_Day51

wy的leetcode刷题记录_Day51 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间:2022-11-24 前言 目录wy的leetcode刷题记录_Day51声明前言795. 区间子数组个数题目介绍思路代码收获98. 验证二叉搜索树题目介绍思路代码收获795. 区间子数组…

Linux中修改环境变量的几种方法比较分析

修改环境变量的作用 使得命令可以在命令行直接运行 第一种方式,在终端直接使用export **特点:**即可生效,无需重启或刷新文件;终端关闭则失效 第二种方式,修改/etc/profile文件 特点:对所有用户永久有…

算法刷题打卡第29天:省份数量---并查集

省份数量 难度:中等 有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。 省份 是一组直接或间接相连的城市,组内不…

SQL注入漏洞 | iwebsec

文章目录靶场搭建SQL注入漏洞靶场搭建 配置 云服务器:阿里云 系统:CentOS 7.6 靶场:iwebsec CentOS-7.6安装docker 安装iwebsec 启动靶场 docker run --restartalways --name iwebsec -it -dp 8001:80 iwebsec/iwebsec访问不成功 可能是…

希望流程挖掘成为撬动企服市场的突破口 | 专访凡得科技CEO海广跃、首席技术顾问刘聪

2022年,全球流程挖掘市场规模预计将达70多亿人民币,而目前中国流程挖掘行业尚处于市场启蒙期,仅少数大型企业与机构对流程挖掘进行了初步或尝试性的投入。从目前来看,原生流程挖掘厂商会直接面向客户输出流程挖掘能力,…

Spring集合注入

一、环境准备 创建一个Maven项目pom.xml添加Spring依赖resources下添加spring的配置文件applicationContext.xml项目中添加BookDao、BookDaoImpl类 public interface BookDao {public void save(); }public class BookDaoImpl implements BookDao {private int[] array;priva…

容器云平台初始化(harbor的安装部署)

1.虚拟机规划 设备说明主机名接口IP地址虚拟机1MasterEth010.0.0.10/24虚拟机2Node1Eth010.0.0.20/24虚拟机3HarborEth010.0.0.30/24 2.容器云平台初始化(harbor的安装部署) 1.根据规划的IP地址,创建虚拟机,确保网络正常通信。按照规划表修改主机名并关…

Linux-ACL权限

ACL权限简介 ACL:access control list 允许给任何用户或者用户组设置任何文件或者目录的访问权限 查看Linux是否开启ACL dumpe2fs Linux一般都开启了ACL权限,可以使用下面的命令查看分区的ACL权限是否打开 首先可以使用df -h或者lsblk来查看Linux系统…

JioNLP上的那些好用的冷门工具

大家好,JioNLP(https://github.com/dongrixinyu/JioNLP)目前已经在Github上有了1600星的点赞,下载安装量大概有几万了。 被使用最多的功能,也是被问得最多的,主要是关键短语抽取、时间语义解析、地址按省市县三级解析等等。其它功…

程序员迷茫:30岁以上的“大龄程码农”出路在哪?java码农该怎么办?

程序员生存、成功、制胜的法则源自IT精英的职业发展秘诀热爱工作,享受生活 为什么程序员过了30就不行了? 我们被固定在“敲代码”的坑里,一干就是10年,再干别的早已不会。敲代码已经成了一项流水线般的工作,就像搬砖工…

Postman非GUI运行脚本工具Newman的安装简介

一、Newman简介 Newman是为Postman而生, 专门用来运行Postman编写好的脚本;使用Newman, 你可以很方便的用命令行来执行postman collections 二、Newman安装 1.先下载Node.js https://nodejs.org/zh-cn/download/ 根据自己电脑系统及位数…