背景:线上 Redis
偶尔发生执行命令超时的异常:Command timed out after 1 minute(s)
,但是短时间又找不到具体原因,就想着把执行命令超时时间设置的短一点,查询 Redis
超时以后走 DB
,临时解决一下问题,然后再排查超时的具体原因,但是根据官方文档设置 spring.redis.timeout=2000
以后,并没有生效,也不知道原因,最后用 java
代码配置成功了,这里记录一下配置方法。
import io.lettuce.core.ClientOptions;
import io.lettuce.core.SocketOptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
/**
* @author liuyuan
* @version RedisConfig.java, v 0.1 2024-08-05 15:43
*/
@Slf4j
@Configuration
@EnableRedisRepositories
public class RedisConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Value("${spring.redis.database}")
private int redisDatabase;
// 这里自定义了名称,是因为公司三方包里面已经有一个 RedisConnectionFactory 了,不换名称,不会加载
@Bean
@Primary
public RedisConnectionFactory customRedisConnectionFactory(LettuceClientConfiguration clientConfiguration) {
log.info("RedisConfig.customRedisConnectionFactory() init.........");
RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
standaloneConfiguration.setHostName(redisHost);
standaloneConfiguration.setPort(redisPort);
standaloneConfiguration.setDatabase(redisDatabase);
return new LettuceConnectionFactory(standaloneConfiguration, clientConfiguration);
}
@Bean
public LettuceClientConfiguration clientConfiguration() {
log.info("RedisConfig.clientConfiguration() init.........");
SocketOptions socketOptions = SocketOptions.builder()
.connectTimeout(Duration.ofSeconds(1)) // 设置连接超时时间
.build();
ClientOptions clientOptions = ClientOptions.builder()
.autoReconnect(true) // 是否自动重连
.pingBeforeActivateConnection(true) // 是否在激活连接前发送 PING 命令
.cancelCommandsOnReconnectFailure(false) // 是否在重连失败时取消命令
.disconnectedBehavior(ClientOptions.DisconnectedBehavior.ACCEPT_COMMANDS) // 设置断开连接时的行为
.socketOptions(socketOptions)
.build();
return LettuceClientConfiguration.builder()
.commandTimeout(Duration.ofSeconds(1)) // 设置命令执行超时时间
.clientOptions(clientOptions)
.build();
}
// 原本到上面为止,配置已经完成了,但是还是因为公司三方包里面已经有一个 RedisConnectionFactory 了,所以这里需要重新设置才会生效
// 如果只有一个 RedisConnectionFactory,下面的可以不要
@Bean
@Primary
public StringRedisTemplate stringRedisTemplate(@Qualifier("customRedisConnectionFactory") RedisConnectionFactory connectionFactory) {
log.info("RedisConfig.stringRedisTemplate() init.........");
return new StringRedisTemplate(connectionFactory);
}
@Bean(name = "redisTemplate")
public RedisTemplate<String, String> redisTemplate(@Qualifier("customRedisConnectionFactory") RedisConnectionFactory connectionFactory) {
log.info("RedisConfig.redisTemplate() init.........");
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}