配置线程池的概念

了解这些概念以避免资源耗尽和拥塞

本节旨在帮助您了解如何为 Keycloak 配置线程池和连接池的注意事项和最佳实践。有关应用此配置的示例,请访问 使用 Keycloak 运算符为 HA 部署 Keycloak

概念

Quarkus 执行程序池

Keycloak 请求以及阻塞探测由执行程序池处理。根据可用的 CPU 内核数量,它具有 50 个或更多线程的最大大小。线程根据需要创建,并在不再需要时结束,因此系统会自动扩展和缩减。Keycloak 允许通过 http-pool-max-threads 配置选项配置最大线程池大小。有关示例,请参见 使用 Keycloak 运算符为 HA 部署 Keycloak

在 Kubernetes 上运行时,请调整工作线程的数量,以避免创建超过 CPU 限制允许的 Pod 负载,从而避免节流,这会导致拥塞。在物理机上运行时,请调整工作线程的数量,以避免创建超过节点可以处理的负载,从而避免拥塞。拥塞会导致响应时间更长、内存使用量增加,最终导致系统不稳定。

理想情况下,您应该从较低的线程限制开始,并根据目标吞吐量和响应时间进行调整。当负载和线程数量增加时,数据库连接也会成为瓶颈。如果请求在 5 秒内无法获取数据库连接,它将失败并显示类似 无法获取 JDBC 连接 的日志消息。调用方将收到带有 5xx HTTP 状态码的响应,表示服务器端错误。

如果您过度增加数据库连接数量和线程数量,系统将在高负载下出现拥塞,请求会排队,这会导致性能下降。数据库连接数量通过 数据库 设置 db-pool-initial-sizedb-pool-min-sizedb-pool-max-size 分别进行配置。较低的数字可以确保所有客户端的快速响应时间,即使在偶尔出现负载峰值时出现请求失败的情况也是如此。

JGroups 连接池

这目前仅适用于单站点设置。在具有外部 Infinispan 的多站点设置中,这不再是限制。

集群中所有 Keycloak 节点中的执行器线程总数不应超过 JGroups 线程池中可用的线程数量,以避免错误 org.jgroups.util.ThreadPool: thread pool is full。要查看错误首次发生时的情况,需要将系统属性 jgroups.thread_dumps_threshold 设置为 1,否则该消息仅在拒绝 10000 个请求后才会出现。

JGroup 线程数量默认情况下为 200。虽然可以使用 Java 系统属性 jgroups.thread_pool.max_threads 进行配置,但我们建议将其保留为该值。实验表明,集群中 Quarkus 工作线程的总数不能超过每个节点中 JGroup 线程池中 200 个线程的数量,以避免 JGroups 通信中的死锁。对于具有四个 Pod 的 Keycloak 集群,每个 Pod 应该有 50 个 Quarkus 工作线程。使用 Keycloak 配置选项 http-pool-max-threads 配置 Quarkus 工作线程的最大数量。

使用指标来监控池中的 JGroup 线程总数以及池中活动的线程。当使用 TCP 作为 JGroups 传输协议时,指标 vendor_jgroups_tcp_get_thread_pool_sizevendor_jgroups_tcp_get_thread_pool_size_active 可用于监控。当使用 UDP 时,指标 vendor_jgroups_udp_get_thread_pool_sizevendor_jgroups_udp_get_thread_pool_size_active 可用。这对于监控限制 Quarkus 线程池大小是否将活动 JGroup 线程的数量保持在最大 JGroup 线程池大小以下非常有用。

负载卸载

默认情况下,Keycloak 会无限期地排队所有传入请求,即使请求处理停滞也是如此。这将使用 Pod 中的额外内存,可能会耗尽负载均衡器中的资源,并且请求最终会在客户端超时,而客户端不知道请求是否已处理。要限制 Keycloak 中排队的请求数量,请设置一个额外的 Quarkus 配置选项。

配置 http-max-queued-requests 以指定最大队列长度,以便在超过此队列大小后实现有效的负载卸载。假设 Keycloak Pod 每秒处理大约 200 个请求,那么 1000 个队列将导致最大等待时间约为 5 秒。

当此设置处于活动状态时,超过排队请求数量的请求将返回 HTTP 503 错误。Keycloak 会在日志中记录错误消息。

探测

Keycloak 的存活探测是非阻塞的,以避免在高负载下重新启动 Pod。

整体健康探测和就绪探测在某些情况下可能会阻塞以检查与数据库的连接,因此它们可能会在高负载下失败。因此,Pod 可能会在高负载下变得不可用。

操作系统资源

为了让 Java 创建线程,在 Linux 上运行时,它需要有可用的文件句柄。因此,打开的文件数量(在 Linux 上检索为 ulimit -n)需要为 Keycloak 提供空间以增加所需的线程数量。每个线程还会消耗内存,并且容器内存限制需要设置为允许此值,否则 Pod 将被 Kubernetes 杀死。

在本页上