Amazon ECS 上的 Keycloak 集群失败(org.infinispan.commons.CacheException:缓存的初始状态传输超时)

Keycloak cluster fails on Amazon ECS (org.infinispan.commons.CacheException: Initial state transfer timed out for cache)

我正在尝试部署 2 个 Keycloak docker images (6.0.1) on Amazon ECS (Fargate) using the built-in ECS Service Discovery mecanism 的集群(使用 DNS_PING)。

环境:

JGROUPS_DISCOVERY_PROTOCOL=dns.DNS_PING
JGROUPS_DISCOVERY_PROPERTIES=dns_query=my.services.internal,dns_record_type=A
JGROUPS_TRANSPORT_STACK=tcp <---(also tried udp)

实例 IP 从 Route53 私有命名空间正确解析,它们相互发现没有任何问题(x.x.x.138 首先启动,然后 x.x.x.76)。

二审:

[org.jgroups.protocols.dns.DNS_PING] (ServerService Thread Pool -- 58) ip-x.x.x.76: entries collected from DNS (in 3 ms): [x.x.x.76:0, x.x.x.138:0]
[org.jgroups.protocols.dns.DNS_PING] (ServerService Thread Pool -- 58) ip-x.x.x.76: sending discovery requests to hosts [x.x.x.76:0, x.x.x.138:0] on ports [55200 .. 55200]
[org.jgroups.protocols.pbcast.GMS] (ServerService Thread Pool -- 58) ip-x.x.x.76: sending JOIN(ip-x-x-x-76) to ip-x-x-x-138

并且在第一个实例中:

[org.infinispan.CLUSTER] (thread-8,ejb,ip-x-x-x-138) ISPN000094: Received new cluster view for channel ejb: [ip-x-x-x-138|1] (2) [ip-x-x-x-138, ip-172-x-x-x-76]
[org.infinispan.remoting.transport.jgroups.JGroupsTransport] (thread-8,ejb,ip-x-x-x-138) Joined: [ip-x-x-x-76], Left: []
[org.infinispan.CLUSTER] (thread-8,ejb,ip-x-x-x-138) ISPN100000: Node ip-x-x-x-76 joined the cluster
[org.jgroups.protocols.FD_SOCK] (FD_SOCK pinger-12,ejb,ip-x-x-x-76) ip-x-x-x-76: pingable_mbrs=[ip-x-x-x-138, ip-x-x-x-76], ping_dest=ip-x-x-x-138

看来我们有一个工作集群。不幸的是,第二个实例最终失败并出现以下异常:

Caused by: org.infinispan.commons.CacheException: Initial state transfer timed out for cache work on ip-x-x-x-76

在这发生之前,我看到一堆故障发现任务suspecting/unsuspecting相反的实例:

[org.jgroups.protocols.FD_ALL] (Timer runner-1,null,null) haven't received a heartbeat from ip-x-x-x-76 for 60016 ms, adding it to suspect list
[org.jgroups.protocols.FD_ALL] (Timer runner-1,null,null) ip-x-x-x-138: suspecting [ip-x-x-x-76]
[org.jgroups.protocols.FD_ALL] (thread-9,ejb,ip-x-x-x-138) Unsuspecting ip-x-x-x-76
[org.jgroups.protocols.FD_SOCK] (thread-9,ejb,ip-x-x-x-138) ip-x-x-x-138: broadcasting unsuspect(ip-x-x-x-76)

在 Infinispan 端(缓存),一切似乎都正确发生,但我不确定。每个缓存都是 "rebalanced",每个 "rebalance" 似乎都以,例如:

结尾
[org.infinispan.statetransfer.StateConsumerImpl] (transport-thread--p24-t2) Finished receiving of segments for cache offlineSessions for topology 2.

感觉像是连接问题,但是这两个实例之间的所有端口都完全开放,包括 TCP 和 UDP。

有什么想法吗?有人成功地在 ECS (fargate) 上配置了这个吗?

更新 1 第二个实例最初关闭不是因为 "Initial state transfer timed out .." 错误,而是因为健康检查花费的时间比配置的宽限期长。尽管如此,对于 2 个健康的实例,我每 2 个查询收到一次“404 - Not Found”,告诉我确实存在缓存问题。

在当前的keycloak docker镜像(6.0.1)中,默认栈是UDP。根据 this,版本 7.0.0 将默认为 TCP,并且还将引入一个变量来切换堆栈 (JGROUPS_TRANSPORT_STACK)。

在 Amazon ECS 中使用 UDP 堆栈将 "partially" 工作,这意味着发现将工作,集群将形成,但 Infinispan 缓存将无法在实例之间同步,这将产生不稳定的错误.可能有一种方法可以让它工作 "as-is",但在检查 VPC 流日志时我没有看到实例之间有任何阻塞。

解决方法是通过直接在文件 /opt/jboss/keycloak/standalone/configuration/standalone-ha.xml:

中的图像中修改 JGroups 堆栈来切换到 TCP
<subsystem xmlns="urn:jboss:domain:jgroups:6.0">                                                                                                                                                                             
     <channels default="ee">                                                                                                                                                                                                      
         <channel name="ee" stack="tcp" cluster="ejb"/>   <-- set stack to tcp                                                                                                                                                                    
     </channels>

然后提交新镜像:

docker commit -m="TCP cluster stack" CONTAINER_ID jboss/keycloak:6.0.1-tcp-cluster

Tag/Push 将映像发送到 Amazon ECR,并确保在您的 Amazon ECS 任务之间的安全组中接受端口 7600。