Skip to content

Spring Data Redis 2.2.1 broke Sentinel compatibility #18942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
OrangeDog opened this issue Nov 8, 2019 · 7 comments
Closed

Spring Data Redis 2.2.1 broke Sentinel compatibility #18942

OrangeDog opened this issue Nov 8, 2019 · 7 comments
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid

Comments

@OrangeDog
Copy link
Contributor

See DATAREDIS-1045.

For setups where redis and sentinel use different passwords, spring.redis.sentinel.password should be implemented.

For setups where redis has a password but sentinel doesn't it needs to be disabled in some way.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 8, 2019
@OrangeDog
Copy link
Contributor Author

In the latter situation you get this error. Apparently the solution is to override LettuceConnectionFactory#createClient in some way.

org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Cannot connect to a Redis Sentinel: [RedisURI [host='localhost', port=26379]]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1200)
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getConnection(LettuceConnectionFactory.java:1179)
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getSharedConnection(LettuceConnectionFactory.java:942)
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getConnection(LettuceConnectionFactory.java:353)
	at org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration$EnableRedisKeyspaceNotificationsInitializer.afterPropertiesSet(RedisHttpSessionConfiguration.java:331)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1862)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1799)
	... 16 common frames omitted
Caused by: io.lettuce.core.RedisConnectionException: Cannot connect to a Redis Sentinel: [RedisURI [host='localhost', port=26379]]
	at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:72)
	at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56)
	at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:234)
	at io.lettuce.core.RedisClient.connect(RedisClient.java:207)
	at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.lambda$getConnection$1(StandaloneConnectionProvider.java:115)
	at java.base/java.util.Optional.orElseGet(Optional.java:369)
	at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.getConnection(StandaloneConnectionProvider.java:115)
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1198)
	... 22 common frames omitted
Caused by: io.lettuce.core.RedisConnectionException: Cannot connect Redis Sentinel at RedisURI [host='localhost', port=26379]
	at io.lettuce.core.RedisClient.lambda$connectSentinelAsync$9(RedisClient.java:555)
	at reactor.core.publisher.Mono.lambda$onErrorMap$30(Mono.java:3252)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:88)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:100)
	at reactor.core.publisher.Operators.error(Operators.java:182)
	at reactor.core.publisher.MonoError.subscribe(MonoError.java:52)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4087)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:97)
	at reactor.core.publisher.MonoCompletionStage.lambda$subscribe$0(MonoCompletionStage.java:80)
	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859)
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
	at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2088)
	at io.lettuce.core.protocol.AsyncCommand.doCompleteExceptionally(AsyncCommand.java:139)
	at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120)
	at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111)
	at io.lettuce.core.protocol.CommandWrapper.complete(CommandWrapper.java:59)
	at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:654)
	at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:614)
	at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:565)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514)
	at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: io.lettuce.core.RedisCommandExecutionException: ERR unknown command 'AUTH'
	at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135)
	at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:108)
	... 22 common frames omitted

@wilkinsona
Copy link
Member

@mp911de @christophstrobl can you please advise on what, if anything, we need to do in Boot to accomodate the Data Redis change?

@mp911de
Copy link
Member

mp911de commented Nov 8, 2019

With Spring Data Redis 2.2, we introduced support for Sentinel authentication. That is, reusing authentication from spring.redis.password for Redis data nodes also with Redis Sentinel nodes who serve as cluster coordinator.

That functionality gets only applied when using the Lettuce client. The Jedis client does not support Sentinel authentication yet. So we're in a situation where a potential property spring.redis.sentinel.password would get applied to one driver implementation but not the other one.

Reusing spring.redis.password for an additional type of server breaks functionality for arrangements that do not use the same password for data and sentinel nodes.

From a Spring Data Redis perspective, we could roll back that change and introduce a separate configuration property that is considered only when Redis is used in Sentinel mode.

From a configuration perspective, it's not clear to me how to properly surface the aspect that Jedis does not support this configuration property.

@OrangeDog
Copy link
Contributor Author

N.B. this change was in 2.2.1, not 2.2.0

@wilkinsona
Copy link
Member

wilkinsona commented Nov 8, 2019

Thanks, @mp911de. We've been applying the password to the sentinel config since 2.0.0.M3 so it sounds like Data Redis is now doing something itself that we've been doing for a while, and the way that Data Redis is doing it has broken something.

@OrangeDog If you'd like us to consider more fine-grained control with a sentinel-specific password, please open a separate enhancement request. I suspect the current breakage needs to be fixed in Data Redis, but I'll wait for confirmation from @mp911de before closing this.

@mp911de
Copy link
Member

mp911de commented Nov 11, 2019

Reuse of spring.redis.password for Sentinels is new functionality in Spring Data Redis (planned for 2.2.0, shipped with 2.2.1). Regardless of whether this feature should have been shipped with 2.2.0 or whether it was shipped in a bugfix release, we've realized that making a new assumption for existing configuration properties affects too many users in a breaking way without the possibility to disable that behavior.

We can close this ticket here. With DATAREDIS-1060, we will revert to the previous behavior and introduce a new property RedisSentinelConfiguration.sentinelPassword that can be used to opt-in for Sentinel authentication.

Sorry for the inconvenience.

@wilkinsona
Copy link
Member

Thanks, @mp911de.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

4 participants