如何解决Keycloak:从嵌入式到远程 Infinispan 重建时到 Infinispan 集群的持久缓存同步超时
我正在将 keycloak (v.3.4.0 final) 从使用嵌入式 infinispan 切换到专用的远程 infinispan 集群 (v8.2.8.final)。我已经完成了升级过程,在较低的环境中使用 infinispan 集群作为远程存储,没有问题。在我的生产设置中,我在 InfinispanCacheInitializer 上遇到超时异常
Keycloak 发生错误的地方:https://github.com/keycloak/keycloak/blob/3.4.2.Final/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java#L117
ERROR [org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer] (ServerService Thread Pool -- 54) ExecutionException when computed future. Errors: 13: java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutExc
eption
at org.infinispan.distexec.DefaultExecutorService$distributedTaskPart.get(DefaultExecutorService.java:850)
at org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer.startLoading(InfinispanCacheInitializer.java:102)
at org.keycloak.models.sessions.infinispan.initializer.DBLockBasedCacheInitializer.startLoading(DBLockBasedCacheInitializer.java:75)
at org.keycloak.models.sessions.infinispan.initializer.CacheInitializer.loadSessions(CacheInitializer.java:41)
at org.keycloak.models.sessions.infinispan.InfinispanUserSessionProviderFactory$2.run(InfinispanUserSessionProviderFactory.java:150)
at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:227)
at org.keycloak.models.sessions.infinispan.InfinispanUserSessionProviderFactory.loadPersistentSessions(InfinispanUserSessionProviderFactory.java:137)
at org.keycloak.models.sessions.infinispan.InfinispanUserSessionProviderFactory$1.onEvent(InfinispanUserSessionProviderFactory.java:108)
at org.keycloak.services.DefaultKeycloakSessionFactory.publish(DefaultKeycloakSessionFactory.java:68)
at org.keycloak.services.resources.KeycloakApplication$2.run(KeycloakApplication.java:165)
at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:227)
at org.keycloak.services.resources.KeycloakApplication.<init>(KeycloakApplication.java:158)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.jboss.resteasy.core.ConstructorInjectorImpl.construct(ConstructorInjectorImpl.java:150)
at org.jboss.resteasy.spi.ResteasyProviderFactory.createProviderInstance(ResteasyProviderFactory.java:2298)
at org.jboss.resteasy.spi.ResteasyDeployment.createApplication(ResteasyDeployment.java:340)
at org.jboss.resteasy.spi.ResteasyDeployment.start(ResteasyDeployment.java:253)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerdispatcher.init(ServletContainerdispatcher.java:120)
at org.jboss.resteasy.plugins.server.servlet.HttpServletdispatcher.init(HttpServletdispatcher.java:36)
at io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed(LifecyleInterceptorInvocation.java:117)
at org.wildfly.extension.undertow.security.RunAsLifecycleInterceptor.init(RunAsLifecycleInterceptor.java:78)
at io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed(LifecyleInterceptorInvocation.java:103)
at io.undertow.servlet.core.ManagedServlet$DefaultInstanceStrategy.start(ManagedServlet.java:250)
at io.undertow.servlet.core.ManagedServlet.createServlet(ManagedServlet.java:133)
at io.undertow.servlet.core.DeploymentManagerImpl$2.call(DeploymentManagerImpl.java:565)
at io.undertow.servlet.core.DeploymentManagerImpl$2.call(DeploymentManagerImpl.java:536)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at io.undertow.servlet.core.DeploymentManagerImpl.start(DeploymentManagerImpl.java:578)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
at org.jboss.threads.JBossthread.run(JBossthread.java:320)
Caused by: java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask.get(FutureTask.java:205)
at org.infinispan.commons.util.concurrent.NotifyingFutureImpl.get(NotifyingFutureImpl.java:88)
at org.infinispan.distexec.DefaultExecutorService$LocaldistributedTaskPart.getResult(DefaultExecutorService.java:1083)
at org.infinispan.distexec.DefaultExecutorService$distributedTaskPart.innerGet(DefaultExecutorService.java:868)
at org.infinispan.distexec.DefaultExecutorService$distributedTaskPart.get(DefaultExecutorService.java:848)
... 44 more
概述
- Keycloak 版本:3.4.0.final(知道这是一个旧版本 - 并与自定义一起使用
实施 - 不容易升级)
- 启动脚本:
ExecStart={{ keycloak_jboss_home }}/bin/standalone.sh -b
使用 standalone.xml
- 启动脚本:
- Infinispan 版本:8.2.8.final
- 从嵌入式本地缓存切换到以下缓存的远程存储配置:
- offline_user_session 计数:约 300 万
为了从数据库测试这个大小的缓存同步,我更新了 standalone.xml 和 standalone.conf 文件中的超时配置
keycloak/keycloak-3.4.0.Final/standalone/configuration/standalone.xml 将协调器超时更新为 3 小时并注释掉查询超时
<subsystem xmlns="urn:jboss:domain:transactions:4.0">
<core-environment>
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
<coordinator-environment default-timeout="10800"/>
</subsystem>
....
....
..
<!-- <timeout>
<query-timeout>15</query-timeout>
</timeout>-->
/keycloak/keycloak-3.4.0.Final/bin/standalone.conf 将阻塞超时添加到 JAVA_OPTS
JAVA_OPTS="$JAVA_OPTS -Djboss.modules.system.pkgs=$JBOSS_MODULES_SYstem_PKGS -Djava.awt.headless=true -Djboss.as.management.blocking.timeout=10800"
我想指出的是,在最初几次尝试使其工作后,当恢复使用 keycloak 节点上的嵌入式缓存时,数据同步良好,在大约 1.5 小时内没有任何超时错误。
keycloak 启动后大约需要 60 分钟才能开始同步离线用户会话。查看 keycloak 正在运行的查询,我可以看到在开始将 offline_user_session 记录同步到 offlinesessions 缓存后大约 5-10 分钟发生超时错误
在超时之前运行的查询是:
-
delete from OFFLINE_CLIENT_SESSION where not (exists (select persistent1_.USER_SESSION_ID from OFFLINE_USER_SESSION persistent1_ where persistent1_.USER_SESSION_ID=OFFLINE_CLIENT_SESSION.USER_SESSION_ID))
-
update OFFLINE_USER_SESSION set LAST_SESSION_REFRESH=$1
-
DELETE FROM jgroupsPING WHERE own_addr=$1 AND cluster_name=$2
-
select count(persistent0_.OFFLINE_FLAG) as col_0_0_ from OFFLINE_USER_SESSION persistent0_ where persistent0_.OFFLINE_FLAG=$1
-
select userrolema0_.ROLE_ID as col_0_0_ from USER_ROLE_MAPPING userrolema0_ where userrolema0_.USER_ID=$1
-
select userentity0_.ID as ID1_76_,userentity0_.CREATED_TIMESTAMP as CREATED_2_76_,userentity0_.EMAIL as EMAIL3_76_,userentity0_.EMAIL_CONSTRAINT as EMAIL_CO4_76_,userentity0_.EMAIL_VERIFIED as EMAIL_VE5_76_,userentity0_.ENABLED as ENABLED6_76_,userentity0_.FEDERATION_LINK as FEDERATI7_76_,userentity0_.FirsT_NAME as FirsT_NA8_76_,userentity0_.LAST_NAME as LAST_NAM9_76_,userentity0_.NOT_BEFORE as NOT_BEF10_76_,userentity0_.REALM_ID as REALM_I11_76_,userentity0_.SERVICE_ACCOUNT_CLIENT_LI
-
select attributes0_.USER_ID as USER_ID4_72_0_,attributes0_.ID as ID1_72_0_,attributes0_.ID as ID1_72_1_,attributes0_.NAME as NAME2_72_1_,attributes0_.USER_ID as USER_ID4_72_1_,attributes0_.VALUE as VALUE3_72_1_ from USER_ATTRIBUTE attributes0_ where attributes0_.USER_ID=$1
-
select persistent0_.OFFLINE_FLAG as OFFLINE_1_47_,persistent0_.USER_SESSION_ID as USER_SES2_47_,persistent0_.DATA as DATA3_47_,persistent0_.LAST_SESSION_REFRESH as LAST_SES4_47_,persistent0_.REALM_ID as REALM_ID5_47_,persistent0_.USER_ID as USER_ID6_47_ from OFFLINE_USER_SESSION persistent0_ where persistent0_.OFFLINE_FLAG=$1 order by persistent0_.USER_SESSION_ID limit $2 offset $3
我设置了 Infinispan WebConsole UI,所以我可以看到缓存同步的进度。每次收到 15k 个条目(大约 300 万个)
我不肯定这里的问题,因为从数据库同步离线会话对于嵌入式版本工作正常,但对于远程 infinispan 启动,它似乎有问题,要么是查询的批处理,要么是我的另一种配置infinispan侧的keycloak中的任何一个缺失。
解决方法
将 keycloak 版本升级到 5.0 解决了缓存同步因期货而超时的问题。升级 4.7 之后的主要版本 -> 在缓存同步时间方面有一些代码更改,现在大约 300 万条记录需要大约 30-40 分钟。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。