Kubernetes 的错误消息和解决方案

本文档描述了在 Kubernetes 上运行 Keycloak 基准测试套件时遇到的常见错误消息及其解决方案。

Keycloak 消息 ERROR: Failed to obtain JDBC connection

上下文

当使用关系型数据库(如 PostgreSQL 或 CockroachDB)运行 Keycloak 时,可能会出现此错误消息。

类似的其他错误消息

  • 无法获取 JDBC 连接

  • 抱歉,获取超时!

这可能在启动过程中发生,然后启动失败。它也可能在负载测试期间发生,此时 Keycloak 创建新的数据库连接。

原因

数据库要么未启动,要么当前设置中已用尽数据库连接数。

解决方案
  • 确保数据库正在运行。

  • 确保数据库没有重新启动,例如由于内存不足问题。

  • 确保总的数据库连接数不超过数据库的最大连接数。有关详细信息,请参阅 Keycloak 部署配置选项 KC_DB_*

  • 确保 Keycloak 不会尝试使用超过配置的最大连接数的连接。

注意
  • 在高负载下,数据库连接数通常是系统的限制因素。Keycloak 遇到“抱歉,获取超时”并向调用者返回 HTTP 5xx 代码是一种合理的负载卸载机制。有关详细信息,请参阅 在生产环境中运行

Keycloak 消息 prepared transactions are disabled

完整消息
org.postgresql.util.PSQLException: ERROR: prepared transactions are disabled.
Hint: Set max_prepared_transactions to a nonzero value.
上下文

当事务管理器或 Quarkus 在一个请求中处理多个事务,并且其中一个事务属于 PostgreSQL 数据库时,就会发生这种情况。

原因

一旦 Quarkus 的事务管理器捆绑了两个事务,它就会在准备所有事务后发送 PREPARE TRANSACTION 命令到数据库,然后发送提交命令。为了使这能够正常工作,数据库需要设置 max_prepared_transactions 参数。

影响

对 PostgreSQL 数据库的任何事务都不会成功。

解决方案

将参数 -c max_prepared_transactions=xxx 传递给数据库。对于 Kubernetes 设置中的容器化数据库,这已在 postgres-deployment.yaml 中配置。

Keycloak 消息 ARJUNA012225: cannot access root of object store

完整消息
ARJUNA012225: FileSystemStore::setupStore - cannot access root of object store: ObjectStore/ShadowNoFileLockStore/defaultStore/
上下文

当事务管理器或 Quarkus 在一个请求中处理多个事务并尝试在本地持久化事务状态时,就会发生这种情况。

原因

Keycloak 容器中的 Keycloak 工作目录不可写,因此写入状态失败。

影响

参与 JTA 事务的任何存储的任何事务都不会完成,因此 Keycloak 不会启动。

解决方案

通过环境变量 QUARKUS_TRANSACTION_MANAGER_OBJECT_STORE_DIRECTORY 传递一个可写文件夹。这在 keycloak#19384 中为 Keycloak 21.1 上游修复。

Keycloak 消息 'org.jgroups.util.ThreadPool: thread pool is full'

完整消息
org.jgroups.util.ThreadPool`: thread pool is full (max=xx, active=xx); thread dump (dumped once, until thread_dump is reset)
上下文

当 JGroups 中的线程池用完线程时,就会发生这种情况。为了使此消息在使用默认 JGroups 配置时出现,系统属性 jgroups.thread_dumps_threshold 需要设置为 1,因为否则该消息只会出现在 10000 个线程被拒绝后。

原因

每个 Keycloak Pod 都有执行器线程来运行 RESTEasy 请求。虽然这些线程可以从本地缓存(主缓存或备份缓存)中直接请求数据,但它们需要通过 JGroups 调用远程缓存。虽然这些请求中的一部分可能会被捆绑,但每个调用远程的 Keycloak 请求可能需要使用一个 JGroups 线程。

影响

当 JGroups 在其线程池中用完线程时,它会拒绝并丢弃它即将入队的那些远程调用。这会导致更长的处理时间,最终导致 Infinispan 超时,而 JGroups 是其底层传输协议。

解决方案

集群中所有 Keycloak Pod 的执行器线程总数应该等于 JGroups 线程池的最大大小。

随着 ISPN-14780 在 Keycloak 22.0.2 中得到修复,JGroup 线程数默认为 200,并且可以使用 Java 系统属性 jgroups.thread_pool.max_threads 进行配置。正如实验中所显示的那样,假设一个包含 4 个 Pod 的 Keycloak 集群,每个 Pod 不应该超过 50 个工作线程,这样就不会在 JGroup 线程池中耗尽 200 个线程。使用 Quarkus 配置选项 quarkus.thread-pool.max-threads 来配置最大工作线程数。

请参阅 在生产环境中运行 中的更多信息。