2025-12-29一次 Trino 连接 Hive 的“诡异故障”:GMT+08:00 时区引发的 Catalog 初始化失败

39 阅读6分钟

2025-12-29一次 Trino 连接 Hive 的“诡异故障”:GMT+08:00 时区引发的 Catalog 初始化失败

0. TL;DR

  • 环境组合

    • • Trino:435
    • • JDK:17.0.12
    • • CDH:6.3.2
    • • Hive:2.1.1(Metastore + HiveServer2)
    • • Hive Metastore:thrift://prd-data:9083
    • • HDFS:fs.defaultFS=hdfs://prd-data:8020
    • • 系统时区:GMT+08:00
  • 现象

    • • ClickHouse / MySQL catalog 正常
    • • Hive catalog 一直报:
      Catalog 'hive' failed to initialize and is disabled
    • • Trino 启动日志中出现大量 Guice ERROR_INJECTING_CONSTRUCTOR,核心报错为:
      The datetime zone id 'GMT+08:00' is not recognised
  • 根因

    • • Trino Hive connector 在初始化 Parquet / RCFile 相关组件时,会从配置中拿一个“时区字符串”给 JodaTime:
      DateTimeZone.forID("GMT+08:00")
    • • JDK 的 GMT+08:00Java Time 没问题,但对 Joda Time 来说,这个 ID 不合法,直接抛 IllegalArgumentException,导致 Hive catalog 初始化失败。
  • 解决方案(关键配置)
    etc/catalog/hive.properties 中显式指定 Hive 用到的时间格式时区为 Joda 能识别的 ID,例如:``` connector.name=hive hive.metastore.uri=thrift://prd-data:9083

    # HDFS 支持(根据自己情况) fs.hadoop.enabled=true hive.config.resources=/etc/hive/conf.cloudera.hive/core-site.xml,/etc/hive/conf.cloudera.hive/hdfs-site.xml

    # 关键修复:显式指定时区,绕开 JVM 默认的 GMT+08:00 hive.parquet.time-zone=Asia/Shanghai hive.rcfile.time-zone=Asia/Shanghai hive.orc.time-zone=Asia/Shanghai


1. 背景环境

这次事故的环境大概是这样:

  • 大数据栈:CDH 6.3.2
    • • Hive 2.1.1(由 Cloudera Manager 管理)
    • • Hive Metastore:
      • hive.metastore.uris=thrift://prd-data:9083
      • • warehouse:/user/hive/warehouse
    • • HDFS:
      • fs.defaultFS=hdfs://prd-data:8020
  • 查询引擎:Trino 435
    • • 单机部署,/apps/trino/trino-server-435
    • • JDK 17 安装在 /apps/trino/jdk_17
    • • HTTP 端口:6868
  • 其他 Catalog
    • • ClickHouse(25.3)通过 jdbc catalog 正常工作
    • • MySQL 8(阿里云 RDS)通过 jdbc catalog 正常工作

目标是:
在这台机器上让 Trino 通过 Hive connector 访问 CDH 上的 Hive Metastore + HDFS 数据。


2. 故障现象

Trino 服务启动正常:

systemctl status trino
# Active: active (running)

ClickHouse / MySQL catalog 正常:

SHOW SCHEMAS FROM clickhouse;
SHOW SCHEMAS FROM mysql8;

唯独 Hive:

SHOW SCHEMAS FROM hive;

返回:

Query failed: Catalog 'hive' failed to initialize and is disabled
io.trino.spi.TrinoException: Catalog 'hive' failed to initialize and is disabled

Trino CLI / DBeaver 中行为一致,说明问题不在客户端。


3. 常规排查:确认 Hive 自己没问题

3.1 Metastore 是否正常监听

ss -lntp | grep 9083
# LISTEN 0 50 0.0.0.0:9083 ... java ... HiveMetaStore -p 9083

进程日志:

ps aux | grep HiveMetaStore
# hive ... org.apache.hadoop.hive.metastore.HiveMetaStore -p 9083

Metastore 进程正常。

3.2 配置是否一致

Hive 自己的 hive-site.xml

<property>
  <name>hive.metastore.uris</name>
  <value>thrift://prd-data:9083</value>
</property>

Trino 的 hive.properties

connector.name=hive
hive.metastore.uri=thrift://prd-data:9083

配置一致。

3.3 HDFS 配置文件是否可用

ls -l /etc/hive/conf.cloudera.hive/core-site.xml /etc/hive/conf.cloudera.hive/hdfs-site.xml
# 均存在

core-site.xmlfs.defaultFS 指向同一个 HDFS:

<name>fs.defaultFS</name>
<value>hdfs://prd-data:8020</value>

说明 Hive 集群本身是健康的。问题的焦点在 Trino Hive connector 初始化阶段


4. 关键线索:Guice 报错 + Joda 时区异常

server.log 中搜索 Hive 相关错误:

cd /apps/trino/data/var/log
grep -n "Failed to load catalog hive" server.log
# ...
sed -n '上下若干行' server.log

看到核心堆栈:

[Guice/ErrorInjectingConstructor]: IllegalArgumentException: The datetime zone id 'GMT+08:00' is not recognised
  at ParquetPageSourceFactory.<init>(ParquetPageSourceFactory.java:135)
  while locating ParquetPageSourceFactory
  at HiveModule.configure(HiveModule.java:127)
  ...

Caused by: IllegalArgumentException: The datetime zone id 'GMT+08:00' is not recognised
    at org.joda.time.DateTimeZone.forID(DateTimeZone.java:249)
    at HiveConfig.getParquetDateTimeZone(HiveConfig.java:716)
    ...

还有一段类似的:

Caused by: IllegalArgumentException: The datetime zone id 'GMT+08:00' is not recognised
    at DateTimeZone.forID(DateTimeZone.java:249)
    at HiveConfig.getRcfileDateTimeZone(HiveConfig.java:649)
    at RcFilePageSourceFactory.<init>(RcFilePageSourceFactory.java:79)
    ...

解读:

  • • Trino 在初始化 ParquetPageSourceFactoryRcFilePageSourceFactory 时,会从 HiveConfig 拿时间配置;
  • HiveConfig.getParquetDateTimeZone() / getRcfileDateTimeZone() 内部调用 DateTimeZone.forID()(JodaTime);
  • • 传入的 zone ID 是 "GMT+08:00"
  • • JodaTime 不认这个字符串 → 直接抛 IllegalArgumentException;
  • • Guice 构造这些 bean 时失败 → Hive connector 初始化失败 → catalog 被标记为 disabled。

这一点非常关键:
链路从单纯的 Metastore/HDFS 连通性,收敛到了 Hive connector「内部配置解析」这一层。


5. 根因分析:JVM 默认时区 vs Joda 时区 ID

在 Trino Hive connector 中,时间相关的几个配置大致是这样的(精简概念):

  • hive.parquet.time-zone
  • hive.rcfile.time-zone
  • hive.orc.time-zone

含义:
用于控制读取 ORC/Parquet/RCFile 中时间字段的时区处理。
如果不显式配置,一般会采用 JVM 默认时区

而在这台机器上,JVM 默认时区是:

GMT+08:00

在 JDK / java.time.ZoneId / TimeZone 的世界里,这种写法是可以接受的;
但是 Trino Hive 使用的是 JodaTime,它要求:

  • • 要么是区域名,如 Asia/Shanghai
  • • 要么是纯偏移,如 +08:00

"GMT+08:00" 这样的字符串,对 Joda 来说不合法,于是 DateTimeZone.forID("GMT+08:00") 直接抛异常。

因此,虽然我们压根没在 hive.properties 中配置 hive.parquet.time-zone 这些属性,
但默认行为会把 JVM 默认时区字符串“原封不动地当成配置值”传给 JodaTime,最终导致初始化失败。

这就解释了:

  • • 为什么 clickhouse / mysql8 完全没事:它们用不到 Joda 的这个路径;
  • • 为什么 只要一加载 Hive connector 就报 ERROR_INJECTING_CONSTRUCTOR
    Parquet / RCFile 相关类在构造时就挂掉了。

6. 解决方案:显式指定 Hive 的 time-zone

6.1 在 hive.properties 中设置合理的时区

对本次环境(东八区)来说,推荐设置为 Asia/Shanghai

connector.name=hive
hive.metastore.uri=thrift://prd-data:9083

# HDFS 支持(按实际情况配置)
fs.hadoop.enabled=true
hive.config.resources=/etc/hive/conf.cloudera.hive/core-site.xml,/etc/hive/conf.cloudera.hive/hdfs-site.xml

# 关键修复:显式设置时间格式时区为 Joda 可识别的 ID
hive.parquet.time-zone=Asia/Shanghai
hive.rcfile.time-zone=Asia/Shanghai
hive.orc.time-zone=Asia/Shanghai

保存之后,重启 Trino:

systemctl restart trino
# 或 /apps/trino/current/bin/launcher restart

然后在 CLI 中验证:

jdk_17/bin/java -jar /apps/trino/trino-cli.jar \
  --server http://127.0.0.1:6868 \
  --user trino \
  --password \
  --catalog hive \
  --schema default

trino> SHOW SCHEMAS FROM hive;

此时 Hive catalog 能正常列出 schema,问题解决。

备注:如果不想写区域名,也可以用偏移写法:
hive.parquet.time-zone=+08:00 等,同样能被 Joda 识别。

6.2(可选)在 JVM 层统一设定时区

为了避免将来有其它地方也踩到 GMT+08:00 这个坑,可以在 jvm.config 中增加:

-Duser.timezone=Asia/Shanghai

结合本次配置,jvm.config 末尾类似:

-Xms4G
-Xmx4G
-DHADOOP_USER_NAME=hive
-Duser.timezone=Asia/Shanghai

这不是必须项,但对整体行为更可控。


7. 额外经验:这次排查顺带踩到的其他点

这次事故除了时区问题,其实还顺手排掉了两个常见坑:

7.1 Trino 开启密码认证必须配 internal-communication.shared-secret

  • • 开启密码认证时,我们在 config.properties 中加了:``` http-server.authentication.type=PASSWORD http-server.authentication.allow-insecure-over-http=true
  • • 随后 Trino 启动直接报一堆 Guice 错误,核心提示是:``` Shared secret (internal-communication.shared-secret) is required when authentication is enabled
  • • 解决办法:必须追加一行:``` internal-communication.shared-secret=trino-shared-secret-xxxx
    
    这个值随便生成一个足够长的随机字符串即可(集群多节点时需要一致)。
    
    

7.2 MySQL catalog 配置不要乱写不存在的属性

  • • 一开始 MySQL catalog 写成:``` connector.name=mysql connection-url=jdbc:mysql://host:3306 connection-user=admin_dev connection-password=xxx connection-properties=useUnicode=true&...
  • • Trino 的 MySQL connector 没有 connection-properties 这个配置项
    导致加载 catalog 时直接抛异常 → Catalog 'mysql8' failed to initialize and is disabled
  • • 正确写法是:所有 JDBC 参数拼到 URL 里:``` connector.name=mysql connection-url=jdbc:mysql://host:3306?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false connection-user=admin_dev connection-password=xxx

8. 总结:排查 Trino Catalog 问题的一套套路

这次 Hive 的问题有点“偏门”,但排查过程可以沉淀出一个通用 checklist,供后续参考:

  1. 1. 先确认 Trino 进程健康
    • systemctl status trino / launcher status
    • curl http://127.0.0.1:6868/v1/info
  2. 2. 再确认底层服务健康
    • • Hive Metastore:端口 9083 是否 LISTEN、hive.metastore.uris 是否一致;
    • • HDFS:fs.defaultFS 是否正确;
    • • MySQL/RDS:本机 mysql -h ... 能否连通。
  3. 3. 针对某个 catalog 报 failed to initialize and is disabled
    • • 在 server.log 中搜索:
      • Failed to load catalog hive
      • Caused by:
    • • 往上/往下看 50~100 行,重点关注:
      • • 配置项非法(Unknown configuration property)
      • • 网络异常(ConnectException)
      • • 类加载错误(ClassNotFound / NoSuchMethod)
      • • 这次这种:时区 ID 不被 Joda 识别
  4. 4. 对 Hive 这类复杂 connector,建议从“极简配置”开始
    • • 先只写:``` connector.name=hive hive.metastore.uri=thrift://host:9083
    • • 确认能起,再渐进式加:
      • • HDFS 支持(fs.hadoop.enabled + hive.config.resources
      • • 时区相关配置
      • • 安全相关配置(Kerberos / Ranger 等)
  5. 5. 遇到 Guice 的 ERROR_INJECTING_CONSTRUCTOR 一定不要只看第一行
    真正的根因通常在几十行后的 第一个 Caused by,这次的 GMT+08:00 就是典型代表。

.preview-wrapper pre::before { position: absolute; top: 0; right: 0; color: #ccc; text-align: center; font-size: 0.8em; padding: 5px 10px 0; line-height: 15px; height: 15px; font-weight: 600; } .hljs.code__pre > .mac-sign { display: flex; } .code__pre { padding: 0 !important; } .hljs.code__pre code { display: -webkit-box; padding: 0.5em 1em 1em; overflow-x: auto; text-indent: 0; } h2 strong { color: inherit !important; }

本文使用 文章同步助手 同步