Does the Redis ticket registry support Redis Cluster mode (not Sentinel) in order to provide high availability?
The following link has mentioned that Redis can support Sentinel, but not mention Cluster for configuration.
I have tried to config my CAS server to connect to one Redis Cluster (one master one slave) but no luck. Once I shut down the master node then the service was down immediately and the CAS kept showing the error log below:
cas-overlay-cas-1 | 2023-08-17 10:05:11,262 WARN [io.lettuce.core.protocol.ConnectionWatchdog] - <Cannot reconnect to [XXX.XXX.XXX.XXX:6379]: finishConnect(..) failed: Connection refused: /
XXX.XXX.XXX.XXX:6379>
cas-overlay-cas-1 | 2023-08-17 10:05:31,081 ERROR [org.apereo.cas.ticket.registry.DefaultTicketRegistryCleaner] - <Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Comma
nd timed out after 1 minute(s); nested exception is org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after
1 minute(s)>
cas-overlay-cas-1 | org.springframework.data.redis.connection.ClusterCommandExecutionFailureException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out
after 1 minute(s); nested exception is org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.collectResults(ClusterCommandExecutor.java:267) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandAsyncOnNodes(ClusterCommandExecutor.java:210) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnAllNodes(ClusterCommandExecutor.java:178) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.lettuce.LettuceClusterKeyCommands.keys(LettuceClusterKeyCommands.java:90) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.DefaultedRedisConnection.keys(DefaultedRedisConnection.java:123) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.core.RedisTemplate.lambda$keys$14(RedisTemplate.java:896) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:191) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.core.RedisTemplate.keys(RedisTemplate.java:896) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.apereo.cas.ticket.registry.RedisTicketRegistry.getKeysStream(RedisTicketRegistry.java:198) ~[cas-server-support-redis-ticket-registry-6.6.10.jar!/:6.6.10]
cas-overlay-cas-1 | at org.apereo.cas.ticket.registry.RedisTicketRegistry.getKeysStream(RedisTicketRegistry.java:194) ~[cas-server-support-redis-ticket-registry-6.6.10.jar!/:6.6.10]
cas-overlay-cas-1 | at org.apereo.cas.ticket.registry.RedisTicketRegistry.stream(RedisTicketRegistry.java:164) ~[cas-server-support-redis-ticket-registry-6.6.10.jar!/:6.6.10]
cas-overlay-cas-1 | at org.apereo.cas.ticket.registry.DefaultTicketRegistryCleaner.cleanInternal(DefaultTicketRegistryCleaner.java:63) ~[cas-server-core-tickets-api-6.6.10.jar!/:6.6.10]
cas-overlay-cas-1 | at org.apereo.cas.ticket.registry.DefaultTicketRegistryCleaner.clean(DefaultTicketRegistryCleaner.java:41) ~[cas-server-core-tickets-api-6.6.10.jar!/:6.6.10]
cas-overlay-cas-1 | at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
cas-overlay-cas-1 | at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
cas-overlay-cas-1 | at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
cas-overlay-cas-1 | at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
cas-overlay-cas-1 | at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at com.sun.proxy.$Proxy318.clean(Unknown Source) ~[?:?]
cas-overlay-cas-1 | at org.apereo.cas.config.CasCoreTicketsSchedulingConfiguration$TicketRegistryCleanerScheduler.lambda$clean$0(CasCoreTicketsSchedulingConfiguration.java:104) ~[cas-server-core-tickets-6.6.10.
jar!/:6.6.10]
cas-overlay-cas-1 | at org.apereo.cas.util.function.FunctionUtils.doAndHandle(FunctionUtils.java:313) ~[cas-server-core-util-api-6.6.10.jar!/:6.6.10]
cas-overlay-cas-1 | at org.apereo.cas.config.CasCoreTicketsSchedulingConfiguration$TicketRegistryCleanerScheduler.clean(CasCoreTicketsSchedulingConfiguration.java:104) ~[cas-server-core-tickets-6.6.10.jar!/:6.6
.10]
cas-overlay-cas-1 | at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
cas-overlay-cas-1 | at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
cas-overlay-cas-1 | at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
cas-overlay-cas-1 | at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
cas-overlay-cas-1 | at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.3.22.jar!/:5.3.22]
cas-overlay-cas-1 | at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
cas-overlay-cas-1 | at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) ~[?:?]
cas-overlay-cas-1 | at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[?:?]
cas-overlay-cas-1 | at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
cas-overlay-cas-1 | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
cas-overlay-cas-1 | at java.lang.Thread.run(Thread.java:829) ~[?:?]
cas-overlay-cas-1 | Suppressed: org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)
cas-overlay-cas-1 | at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:70) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.convertToDataAccessException(ClusterCommandExecutor.java:332) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnSingleNode(ClusterCommandExecutor.java:142) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnSingleNode(ClusterCommandExecutor.java:118) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.lambda$executeCommandAsyncOnNodes$0(ClusterCommandExecutor.java:207) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
cas-overlay-cas-1 | at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
cas-overlay-cas-1 | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
cas-overlay-cas-1 | at java.lang.Thread.run(Thread.java:829) ~[?:?]
cas-overlay-cas-1 | Caused by: io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)
cas-overlay-cas-1 | at io.lettuce.core.internal.ExceptionFactory.createTimeoutException(ExceptionFactory.java:59) ~[lettuce-core-6.2.0.RELEASE.jar!/:6.2.0.RELEASE]
cas-overlay-cas-1 | at io.lettuce.core.internal.Futures.awaitOrCancel(Futures.java:246) ~[lettuce-core-6.2.0.RELEASE.jar!/:6.2.0.RELEASE]
cas-overlay-cas-1 | at io.lettuce.core.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:75) ~[lettuce-core-6.2.0.RELEASE.jar!/:6.2.0.RELEASE]
cas-overlay-cas-1 | at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80) ~[lettuce-core-6.2.0.RELEASE.jar!/:6.2.0.RELEASE]
cas-overlay-cas-1 | at com.sun.proxy.$Proxy343.keys(Unknown Source) ~[?:?]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.lettuce.LettuceClusterKeyCommands.lambda$keys$0(LettuceClusterKeyCommands.java:90) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnSingleNode(ClusterCommandExecutor.java:139) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | ... 6 more
cas-overlay-cas-1 | Caused by: org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)
cas-overlay-cas-1 | at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:70) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.convertToDataAccessException(ClusterCommandExecutor.java:332) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnSingleNode(ClusterCommandExecutor.java:142) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnSingleNode(ClusterCommandExecutor.java:118) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.lambda$executeCommandAsyncOnNodes$0(ClusterCommandExecutor.java:207) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
cas-overlay-cas-1 | ... 3 more
cas-overlay-cas-1 | Caused by: io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)
cas-overlay-cas-1 | at io.lettuce.core.internal.ExceptionFactory.createTimeoutException(ExceptionFactory.java:59) ~[lettuce-core-6.2.0.RELEASE.jar!/:6.2.0.RELEASE]
cas-overlay-cas-1 | at io.lettuce.core.internal.Futures.awaitOrCancel(Futures.java:246) ~[lettuce-core-6.2.0.RELEASE.jar!/:6.2.0.RELEASE]
cas-overlay-cas-1 | at io.lettuce.core.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:75) ~[lettuce-core-6.2.0.RELEASE.jar!/:6.2.0.RELEASE]
cas-overlay-cas-1 | at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80) ~[lettuce-core-6.2.0.RELEASE.jar!/:6.2.0.RELEASE]
cas-overlay-cas-1 | at com.sun.proxy.$Proxy343.keys(Unknown Source) ~[?:?]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.lettuce.LettuceClusterKeyCommands.lambda$keys$0(LettuceClusterKeyCommands.java:90) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnSingleNode(ClusterCommandExecutor.java:139) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnSingleNode(ClusterCommandExecutor.java:118) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at org.springframework.data.redis.connection.ClusterCommandExecutor.lambda$executeCommandAsyncOnNodes$0(ClusterCommandExecutor.java:207) ~[spring-data-redis-2.7.2.jar!/:2.7.2]
cas-overlay-cas-1 | at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
cas-overlay-cas-1 | ... 3 more
Not sure my expectation is correct or not, but I would expect the CAS server would make the connection to both master and slave nodes. If one node is died then the CAS server can automatically use the other node for connection. But this seems not the case.
If Redis Cluster can be supported, may I know what config are required?
Below are the configuration that I am trying, which is able to connect to the master node but not the slave one if the master node is died:
cas.ticket.registry.redis.cluster.password=
cas.ticket.registry.redis.cluster.nodes[0].name=
xxx.master.comcas.ticket.registry.redis.cluster.nodes[0].host=
xxx.master.comcas.ticket.registry.redis.cluster.nodes[0].port=6379
cas.ticket.registry.redis.cluster.nodes[0].replica-of=0
cas.ticket.registry.redis.cluster.nodes[0].type=MASTER
cas.ticket.registry.redis.cluster.nodes[1].name=
xxx.slave.comcas.ticket.registry.redis.cluster.nodes[1].host=xxx.slave .com
cas.ticket.registry.redis.cluster.nodes[1].port=6379
cas.ticket.registry.redis.cluster.nodes[1].replica-of=0
cas.ticket.registry.redis.cluster.nodes[1].type=SLAVE
cas.ticket.registry.redis.database=0
cas.ticket.registry.redis.enabled=true
cas.ticket.registry.redis.pool.enabled=false
cas.ticket.registry.redis.host=
xxx.master.comcas.ticket.registry.redis.port=6379
cas.ticket.registry.redis.use-ssl=false
Thx a lot.