
转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权。感谢您喜爱本文,请文明转载,谢谢。
1. 问题
在测试环境运行了3个月的一套测试工具,突然报错了,界面各种Error,数据都显示不出来。
后端数据库是使用容器部署的clickhouse数据库。登录数据库查看database和table,发现database存在,但是table全部没有了。
2. 排查
1)有权限的小伙伴均未删除过表,且查看数据库的语句执行记录,无删除表操作,基本排除人为误删;
2)查看clickhouse挂载到本地的数据目录(对应容器的/var/lib/clickhouse目录),文件完整,且到data目录下找到对应的库目录,可以看到里面的表文件是存在的。
3)尝试登录clickhouse,在database下重建这些table,提示:TABLE_ALREADY_EXISTS
3. 原因
经过排查和查询资料发现,原因在建库的时候建库语句中使用了参数"ENGINE = Memory",这个参数代表数据库的元数据(即库里有几张表、表名叫什么)只缓存在内存中,不会持久化到磁盘。一旦服务发生重启,内存被清空,数据就没有了。
对于持久化引擎(如 MergeTree),数据才会被写入磁盘,写入 /var/lib/clickhouse/data/数据库名/ 目录下。
之所以在/var/lib/clickhouse下还能看到表文件,是因为建表时使用的MergeTree引擎。但因为库是用的memory引擎,在容器发生重启后,内存中的元数据丢失,数据库变成了一个"空壳子",无法与MergeTree 表关联起来。
4. 解决方案
一旦 ClickHouse 服务重启,使用 ENGINE = Memory 创建的表中的数据无法找回。这是该引擎的固有特性,只能删除重建。因此Memory 引擎仅适用于以下特定场景:
-
临时数据:处理查询时用到的外部数据。
-
测试环境:跑一些不要求数据保留的测试用例。
-
缓存或中间结果:行数极少(官方建议不超过1亿行)、允许丢失的极速查询表。
5. 测试复现
5.1 复用记录ClickHouse部署并开通AI远程对接的clickhouse,在clickhouse数据库创建2个测试database
创建带"ENGINE = Memory"参数的database---test
# 创建库test:
CREATE DATABASE test ENGINE = Memory COMMENT 'The memory test database';
# 创建一张表users:
CREATE TABLE users (
id UInt32,
name Test,
age UInt8,
email String,
created_at DateTime
) ENGINE = MergeTree() #为复现问题,依然采用MergeTree引擎
ORDER BY id;
创建不带"ENGINE = Memory"参数的database---test001
# 创建库test001:
CREATE DATABASE test001 COMMENT 'The memory test database';
# 创建一张表users001:
CREATE TABLE users001 (
id UInt32,
name Test,
age UInt8,
email String,
created_at DateTime
) ENGINE = MergeTree()
ORDER BY id;
创建完毕:

创建好后,查看容器的/var/lib/clickhouse目录下的test和test001下的文件,是有差异的:

注意:因为2个库的表都用的ENGINE = MergeTree,才会看到这个目录,如果test库下面的users表使用的是ENGINE = Memory,test下是不会生成users这个目录的,test目录下将会是空的。
5.2 然后重启clickhouse容器

5.3 再次进入容器查看test和test001下面的表,检查表,可以看到test库下面的表没了,而test001下面的表还在:

5.4 进入test下面重新建表,提示表已经存在:

但关联clickhouse的服务已经不停报错表不存在了,无法查询到表和数据。