Doris 4.1.2 Hive Catalog 访问 Kerberos HDFS 时 TGT 到期后未自动续期,需重启 BE 恢复

Viewed 9

问题概述

使用 Doris Hive Catalog 通过 Kerberos 访问 HDFS。BE 重启后查询可以正常运行,但运行超过 Kerberos TGT 的 24 小时有效期后,多个 BE 会陆续或同时无法读取 HDFS 文件,并出现以下错误链:

GSSException: No valid credentials provided
  (Mechanism level: Attempt to obtain new INITIATE credentials failed! (null))

javax.security.auth.login.LoginException: Cannot read from System.in
  at com.sun.security.auth.module.Krb5LoginModule.promptForName(...)

此时在同一节点上使用同一个 principal 和 keytab 手工执行 kinit -kt 可以成功。滚动重启 BE 后,HDFS 查询立即恢复;再次运行超过约 24 小时后可能复现。

初步怀疑:Doris 4.1.2 的 BE/libhdfs 没有成功续期或重新获取 TGT,同时 HdfsMgr 持续复用已经失去有效 Kerberos 凭据的 HDFS Handler。

环境信息

项目 信息
Doris doris-4.1.2-rc01-aec169d2025
部署形态 多 FE、多 BE;多个 BE 均可复现
BE JDK JDK 17,JAVA_HOME=/opt/jdk17/
Catalog HMS/Hive Catalog
Hive Catalog 兼容版本 hive.version=1.2.0
HDFS Kerberos + HA,fs.defaultFS=hdfs://<nameservice>
Hadoop/HDP 服务端版本 例如 HDP 2.6.5 / Hadoop 2.7.x
操作系统 CentOS7.9
Kerberos principal doris@<REALM>
keytab /etc/security/keytabs/doris.keytab,所有参与查询的 BE 上路径一致且 BE 进程用户可读
TGT 生命周期 24 小时
renewable 生命周期 7 天

BE 使用的相关 JVM 参数:

-Djavax.security.auth.useSubjectCredsOnly=false
-Dsun.security.krb5.debug=true

Catalog 关键配置(已脱敏)

CREATE CATALOG `ctl_hive` PROPERTIES (
    "type" = "hms",
    "hive.version" = "1.2.0",
    "hive.metastore.uris" = "thrift://<hms1>:9083,thrift://<hms2>:9083",
    "hive.metastore.service.principal" = "hive/_HOST@<REALM>",
    "hive.metastore.client.principal" = "doris@<REALM>",
    "hive.metastore.client.keytab" = "/etc/security/keytabs/doris.keytab",
    "hive.metastore.authentication.type" = "kerberos",
    "hive.conf.resources" = "<resource-dir>/hive-site.xml",
    "hdfs.authentication.type" = "kerberos",
    "hdfs.authentication.kerberos.principal" = "doris@<REALM>",
    "hdfs.authentication.kerberos.keytab" = "/etc/security/keytabs/doris.keytab",
    "hadoop.config.resources" = "<resource-dir>/core-site.xml,<resource-dir>/hdfs-site.xml",
    "fs.defaultFS" = "hdfs://<nameservice>"
);

/etc/krb5.conf 中相关配置:

[libdefaults]
ticket_lifetime = 24h
renew_lifetime = 7d

复现步骤

  1. 在所有可能参与外表扫描的 BE 上放置同一 principal 对应的 keytab,并确保 BE 进程用户可读。
  2. 创建上述 Kerberos Hive Catalog。
  3. 重启 BE,随后执行 Hive 外表查询,确认可以正常读取 HDFS。
  4. 持续或间歇执行查询,使 HDFS Handler 被创建并重复使用。
  5. 保持 BE 不重启,等待超过 TGT 的 24 小时有效期。
  6. 再次查询 Hive 外表。

实际生产时间线中的一次复现:

2026-10-13 22:00  多个 BE 完成滚动重启,查询正常
2026-10-14 22:00  按 24 小时有效期推算,重启时获取的 TGT 到期
2026-10-15 04:52  多个 BE 查询 HDFS 失败,出现 No valid credentials / Cannot read from System.in

实际结果

典型 BE 日志如下(主机名和 HDFS 路径已脱敏):

Reuse existing HDFS handler, is_kerberos=1,
principal=doris@<REALM>, fs_name=hdfs://<nameservice>

java.io.IOException: Failed on local exception:
javax.security.sasl.SaslException: GSS initiate failed
[Caused by GSSException: No valid credentials provided
(Mechanism level: Attempt to obtain new INITIATE credentials failed! (null))]

Caused by: javax.security.auth.login.LoginException: Cannot read from System.in
    at jdk.security.auth/com.sun.security.auth.module.Krb5LoginModule.promptForName(...)
    at jdk.security.auth/com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(...)

对用户可见的查询错误:

[INTERNAL_ERROR] failed to open /<hdfs-path>/<file>: (255),
reason: LoginException: Cannot read from System.in

期望结果

Catalog 已显式配置 principal 和 keytab,BE 应当在 TGT 到期前:

  1. 使用 keytab 自动续期或重新登录并获取新 TGT;或者
  2. 在凭据失效时让旧 HDFS Handler 失效并重新创建;或者
  3. 至少返回明确的 Kerberos 续票/重新登录失败原因,而不是退化为交互式读取 System.in。

不应要求定期重启 BE 才能长期访问 Kerberos HDFS。

keytab、KDC 与 TGT 生命周期验证

故障期间/故障后,在受影响 BE 上使用相同 keytab 独立申请 TGT 成功:

CCACHE=/tmp/doris_tgt_check_$$

KRB5CCNAME=FILE:$CCACHE \
kinit -V -kt /etc/security/keytabs/doris.keytab 'doris@<REALM>'

KRB5CCNAME=FILE:$CCACHE klist -ef
KRB5CCNAME=FILE:$CCACHE kdestroy

实际签发结果:

Valid starting       Expires              Service principal
2026-10-15 09:45:38  2026-10-16 09:45:39  krbtgt/<REALM>@<REALM>
    renew until 2026-10-22 09:45:39, Flags: FRI

因此可以确认:

  • keytab 在故障时仍然有效;
  • KDC 可以正常签发票据;
  • 实际 TGT 有效期为 24 小时、renewable 窗口为 7 天;
  • 独立 kinit 只验证 keytab/KDC,不代表 BE 进程内部的凭据已刷新。

恢复与重复性

  • 不修改 Catalog、不替换 keytab,仅滚动重启 BE 即可恢复。
  • 多个 BE 均出现过同类错误,不是单节点磁盘或单文件损坏。
  • 错误发生在不同 HDFS 文件/分区上,不是特定数据文件问题。
  • 重启后的恢复具有重复性,因此当前只能通过小于 24 小时的周期性滚动重启规避。

4.1.2 源码中的可疑点

以下内容是基于 doris-4.1.2 源码的初步分析,尚不能单独证明根因,请社区协助确认设计意图。

1. 已设置 keytab 和自动续票开关,但 Doris 自有 ticket-cache 路径被注释

文件:be/src/io/hdfs_builder.cpp

hdfsBuilderSetPrincipal(builder->get(), builder->hdfs_kerberos_principal.c_str());
hdfsBuilderSetKerb5Conf(builder->get(), doris::config::kerberos_krb5_conf_path.c_str());
hdfsBuilderSetKeyTabFile(builder->get(), builder->hdfs_kerberos_keytab.c_str());
hdfsBuilderConfSetStr(builder->get(),
                      "hadoop.kerberos.keytab.login.autorenewal.enabled",
                      "true");
// RETURN_IF_ERROR(builder->set_kerberos_ticket_cache());

同文件中的 HDFSCommonBuilder::set_kerberos_ticket_cache() 实现主体也已整体注释,并标记为 deprecated。

希望确认:当前 Doris 构建使用的 libhdfs 是否确实支持并执行 hadoop.kerberos.keytab.login.autorenewal.enabled=true?续期失败时是否有可观测日志?

2. HDFS Handler 被持续复用,按 Kerberos 生命周期淘汰的代码被注释

文件:be/src/io/fs/hdfs/hdfs_mgr.cpp

bool is_expired = current\_time - entry.second->last_access_time >=
                  _instance_timeout_seconds;

// bool is_krb_expired =
//         entry.second->is_kerberos_auth &&
//         (current_time - entry.second->create_time >=
//          entry.second->ticket_cache->get_ticket_lifetime_sec() / 2);

复用 Handler 时还会更新 last_access_time:

if (it != _fs_handlers.end()) {
    it->second->update_access_time();
    *fs_handler = it->second;
    return Status::OK();
}

对于持续有查询的 Catalog,Handler 可能长期不会因为空闲超时被淘汰。如果其内部 Subject/TGT 没有更新,可能一直复用过期凭据。

当前结论边界

已确认

  • 错误的直接原因是 BE 发起 HDFS Kerberos/GSS 认证时没有有效凭据。
  • Java 随后尝试交互式登录并读取 System.in,后台 BE 无法提供输入,所以出现 Cannot read from System.in。
  • TGT 实际有效期为 24 小时、renewable 窗口为 7 天。
  • 相同 keytab 可以独立成功执行 kinit -kt。
  • 多个 BE 可复现,滚动重启 BE 可以恢复。
  • 日志显示出错时正在 Reuse existing HDFS handler。

高度怀疑但尚未完全证实

  • BE/libhdfs 没有成功执行 TGT 自动续期或 keytab 重新登录。
  • 已缓存的 HDFS Handler/Java Subject 没有加载更新后的凭据。
  • hdfs_builder.cpp 和 hdfs_mgr.cpp 中被注释的 ticket-cache/过期 Handler 逻辑与该现象有关。

尚缺少的证据

  • 自动续票线程是否启动、何时执行、失败原因是什么。
  • BE 内部实际使用的 ccache/Subject 与日志中显示的 cache path 的对应关系。
  • backend_kerberos_ticket_cache 在该 HDFS Catalog 路径下是否应有记录。

当前临时规避方案

由于生产 TGT 只有 24 小时,目前使用带安全门禁的 BE 滚动重启:

  • 每 30 分钟检查一次;
  • 距离上次完整成功满 18 小时才实际滚动重启;
  • Tablet 健康检查不通过时不使用 --force-health,保留安全门禁并在下次调度重试;
  • 仅全部 BE 重启成功后才更新成功时间。

该方案会带来运维复杂度和周期性服务扰动,只是临时规避,不是问题修复。

希望社区协助确认的问题

  1. Doris 4.1.2 中 Hive Catalog/HDFS Kerberos 的预期自动续票机制是什么?
  2. hadoop.kerberos.keytab.login.autorenewal.enabled=true 在 Doris 自带的 libhdfs/JDK 17 路径中是否有效?
  3. set_kerberos_ticket_cache() 及按 ticket 生命周期淘汰 HDFS Handler 的代码为什么被注释?这是暂未完成的功能、已废弃方案,还是由其他机制替代?
  4. 是否存在已知 Issue、修复 PR 或包含修复的版本?
  5. 能否在 GSS No valid credentials 后使当前 HDFS Handler 失效,并使用 Catalog 中的 keytab 重新创建连接?
  6. 社区还需要哪些日志或诊断参数来确认自动续票是否执行?
1 Answers

您好,帮忙提供一下从首次 keytab 登录到首次失败的 jni.log / be.out / be.INFO / be.WARNING,重点包含预计首次刷新点前后的日志信息,您可以加我主页微信,给我发一下这些日志文件。