Springboot2.x.x連接Redis配置整合
目錄:
1、必看前言
- 對於整篇文章要解決的問題要有一個基礎的認知
- 對於lettuce-pool你使用的到底是不是pool
- 了解springboot2.x.x各個版本存在的問題
2、springboot2.x.x - lettuce連接Redis配置方式
3、springboot2.x.x - jedis連接Redis配置方式
1.1.0:對於整篇文章要解決的問題要有一個基礎的認知
1.Redis分成 單實例連接 和 集群連接 兩種方式,連接方式是不一樣的 2.對於兩種連接方式通用的配置就是 資源池設置 和 客戶端名稱設置 資源池設置: 為了統一管理客戶端的連接數及合理調度資源使用 客戶端名稱設置: a.當不同的項目使用同一個redis的時候,一旦redis出現了業務上的tps增長,客戶端連接數增長,bigkey阻塞,如果設置了clientName可以快速的定位到是哪個連接的客戶端引起的 b.對於雲部署的容器可能存在獲取不到客戶端的真實ip的情況,所以設置clientName是最好區分的方式 3.對於集群來說,客戶端除了要維護資源池的配置還要考慮到服務端集群如果做出了更改,客戶端要及時響應刷新本地的集群信息, 這就涉及到了客戶端要設置redis集群的拓撲刷新問題,springboot2.x的不同版本有不同的變化刷新 4.對於使用lettuce pool配置時,你的配置是否真的生效,測試之后再說結論,這么說了肯定是不生效,需要進行配置才會生效,下邊也會提到 5.除了以上不同springboot版本對應的redis的配置不同之外,還有一個問題就是序列化的問題,string類型的序列化就是使用string序列化的方式, 但是對於其余類型來說使用的是jdk的序列化方式,所以無論對於哪種版本我們都需要重寫一下序列化方式
1.1.1:對於lettuce-pool你使用的到底是不是pool
我們在設置lettuce-pool的時候,對比jedis會有兩個問題,對這兩個問題提出解決方案 1.min-idle不生效 2.線程數一直不增長,pool的配置不生效
1.1.2:了解springboot2.x.x各個版本存在的問題
redis集群的拓撲刷新問題,只存在於lettuce的連接方式,jedis是將集群信息放入緩存中的,找不到對應的節點信息的時候會去重新獲取刷新緩存, 在springboot2.3.x以后的版本添加了拓撲刷新的配置,在2.3.x之前的版本需要自己在config文件中去開啟刷新 客戶端名稱配置,在springboot2.2.x以后的版本已經添加了配置,不需要重寫配置,2.2.x之前的版本需要重寫配置
2.2.1:springboot2.x.x - lettuce連接Redis配置方式
連接需要兩個文件, application.yml 配置文件和 RedisConfig.java類
下面描述的 springboot2.x.x各個版本的 RedisConfig.java 類的內容都是以當前的RedisConfig.java類內容為基礎的.
公共配置:
@Configuration public class RedisConfig { /** * lettuce pool springboot2.x.x 獲取pool的工具類 */ public GenericObjectPoolConfig getGenericObjectLettucePoolConfig(RedisProperties redisProperties){ GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig(); genericObjectPoolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle()); genericObjectPoolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle()); genericObjectPoolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive()); genericObjectPoolConfig.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait().toMillis()); //默認值為false,在獲取連接之前檢測是否為有效連接,tps很高的應用可以使用默認值 genericObjectPoolConfig.setTestOnBorrow(false); genericObjectPoolConfig.setTestOnReturn(false); //使用lettuce pool的配置的,需要打開此配置,用於檢測控線連接並回收 genericObjectPoolConfig.setTestWhileIdle(true); return genericObjectPoolConfig; } /** * 自定義序列化方式 */ @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 使用Jackson2JsonRedisSerialize 替換默認序列化 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); // 初始化string的序列化方式 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 redisTemplate.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 redisTemplate.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson redisTemplate.setValueSerializer(stringRedisSerializer); // hash的value序列化方式采用jackson redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
springboot2.3.x-lettuce 配置:👇
application.yml
#springboot2.3.x已經添加了對於lettuce拓撲刷新的配置,也添加了對於客戶端的配置 #--------------------------------springboot2.3.x lettuce配置----------------------------------------------- spring: redis: #單實例連接打開此配置,關閉cluster配置即可 # host: 127.0.0.1 # port: 8510 cluster: nodes: 127.0.0.1:6379,127.0.0.2:6379,127.0.0.3:6379,127.0.0.4:6379,127.0.0.5:6379,127.0.0.6:6379 max-redirects: 3 password: 123456 timeout: 50000 ssl: false database: 0 lettuce: pool: max-active: 10 max-idle: 8 min-idle: 1 max-wait: 5000 time-between-eviction-runs: 1000 # 配置空閑連接回收間隔時間,min-idle才會生效,否則不生效 cluster: refresh: #拓撲刷新開關 adaptive: true #自適應刷新集群 默認false關閉 period: 30000 #定時刷新集群 client-name: AppName #配置客戶端名稱
RedisConfig.java
@Configuration public class RedisConfig { /** * 此配置添加到上邊的RedisConfig.java類中 * springboot2.3.x 使用 lettuce 連接redis單機或集群,需要添加以下的選項 */ @Bean public RedisConnectionFactory connectionFactory(RedisProperties redisProperties) { //添加額外屬性 LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder() .commandTimeout(redisProperties.getTimeout()) .poolConfig(getGenericObjectJedisPoolConfig(redisProperties)) .clientName(redisProperties.getClientName()) .build(); //單機連接配置,單實例redis連接放開下邊注釋,同時注釋掉RedisClusterConfiguration的配置 // RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost(),redisProperties.getPort()); // configuration.setPassword(redisProperties.getPassword()); //集群連接配置 RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes()); configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects()); configuration.setPassword(RedisPassword.of(redisProperties.getPassword())); LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, clientConfig); //如果要使pool參數生效,一定要關閉shareNativeConnection lettuceConnectionFactory.setShareNativeConnection(false); return lettuceConnectionFactory; } }
springboot2.2.x-lettuce 配置:👇
application.yml
#springboot2.2.x沒有添加lettuce的拓撲刷新功能,需要通過配置文件手動添加,clientName的配置功能存在 #--------------------------------springboot2.2.x lettuce配置----------------------------------------------- spring: redis: #單實例連接打開此配置,關閉cluster配置即可 # host: 127.0.0.1 # port: 8510 cluster: nodes: 127.0.0.1:6379,127.0.0.2:6379,127.0.0.3:6379,127.0.0.4:6379,127.0.0.5:6379,127.0.0.6:6379 max-redirects: 3 password: 123456 timeout: 50000 ssl: false database: 0 lettuce: pool: max-active: 10 max-idle: 8 min-idle: 1 max-wait: 5000 time-between-eviction-runs: 1000 # 配置空閑連接回收間隔時間,min-idle才會生效,否則不生效 client-name: AppName #配置客戶端名稱
RedisConfig.java 類
@Configuration public class RedisConfig { /** * 此配置添加到上邊的RedisConfig.java類中 * springboot2.2.x使用 lettuce 連接redis單實例或集群,需要添加以下的選項 * * 在構建LettuceConnectionFactory時,如果不使用內置的destroyMethod,可能會導致Redis連接早於其它Bean被銷毀 */ @Bean(destroyMethod = "destroy") public LettuceConnectionFactory newLettuceConnectionFactory(RedisProperties redisProperties) { // 配置用於開啟自適應刷新和定時刷新。如自適應刷新不開啟,Redis集群變更時將會導致連接異常 ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder() .enablePeriodicRefresh(Duration.ofMinutes(10)) .enableAllAdaptiveRefreshTriggers() .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(10)) .build(); ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder() .topologyRefreshOptions(clusterTopologyRefreshOptions) .build(); LettucePoolingClientConfiguration poolConfiguration = LettucePoolingClientConfiguration.builder() .clientOptions(clusterClientOptions) .clientName(redisProperties.getClientName()) .commandTimeout(redisProperties.getTimeout()) .poolConfig(getGenericObjectLettucePoolConfig(redisProperties)) .build(); //單實例連接時打開此配置,並注釋下邊的RedisClusterConfiguration配置 // RedisConfiguration configuration = new // RedisStandaloneConfiguration(redisProperties.getHost(),redisProperties.getPort()); // ((RedisStandaloneConfiguration) configuration).setPassword(redisProperties.getPassword()); RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes()); configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects()); configuration.setPassword(RedisPassword.of(redisProperties.getPassword())); LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, poolConfiguration); //關閉shareNativeConnection,才能讓lettuce.pool的配置生效,如果共享本地連接已經夠使用了,完全可以不用配置 lettuceConnectionFactory.setShareNativeConnection(false); return lettuceConnectionFactory; } }
springboot2.1.x-lettuce 配置:👇
application.yml
#springboot2.1.x沒有添加lettuce的拓撲刷新功能,需要通過配置文件手動添加,也沒有clientName的配置功能 #--------------------------------springboot2.2.x lettuce配置----------------------------------------------- spring: redis: #單實例連接打開此配置,關閉cluster配置即可 # host: 127.0.0.1 # port: 8510 cluster: nodes: 127.0.0.1:6379,127.0.0.2:6379,127.0.0.3:6379,127.0.0.4:6379,127.0.0.5:6379,127.0.0.6:6379 max-redirects: 3 password: 123456 timeout: 50000 ssl: false database: 0 lettuce: pool: max-active: 10 max-idle: 8 min-idle: 1 max-wait: 5000 time-between-eviction-runs: 1000 # 配置空閑連接回收間隔時間,min-idle才會生效,否則不生效
RedisConfig.java 類
@Configuration public class RedisConfig { /** * 此配置添加到上邊的RedisConfig.java類中 * springboot2.1.x使用 lettuce 連接redis單實例或集群,需要添加以下的選項 * * 在構建LettuceConnectionFactory時,如果不使用內置的destroyMethod,可能會導致Redis連接早於其它Bean被銷毀 */ @Bean(destroyMethod = "destroy") public LettuceConnectionFactory newLettuceConnectionFactory(RedisProperties redisProperties) { // 配置用於開啟自適應刷新和定時刷新。如自適應刷新不開啟,Redis集群變更時將會導致連接異常 ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder() .enablePeriodicRefresh(Duration.ofMinutes(10)) .enableAllAdaptiveRefreshTriggers() .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(10)) .build(); ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder() .topologyRefreshOptions(clusterTopologyRefreshOptions) .build(); LettucePoolingClientConfiguration poolConfiguration = LettucePoolingClientConfiguration.builder() .clientOptions(clusterClientOptions) //客戶端名稱需要在這里寫死 .clientName("AppName") .commandTimeout(redisProperties.getTimeout()) .poolConfig(getGenericObjectLettucePoolConfig(redisProperties)) .build(); //單實例連接時打開此配置,並注釋下邊的RedisClusterConfiguration配置 // RedisConfiguration configuration = new // RedisStandaloneConfiguration(redisProperties.getHost(),redisProperties.getPort()); // ((RedisStandaloneConfiguration) configuration).setPassword(redisProperties.getPassword()); RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes()); configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects()); configuration.setPassword(RedisPassword.of(redisProperties.getPassword())); LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, poolConfiguration); //關閉shareNativeConnection,才能讓lettuce.pool的配置生效,如果共享本地連接夠實用完全可以不配置 lettuceConnectionFactory.setShareNativeConnection(false); return lettuceConnectionFactory; } }
3.3.1:springboot2.x.x - jedis連接Redis配置方式
連接需要兩個文件, application.yml 配置文件和 RedisConfig.java類,對於jedis而言,
不存在redis集群的拓撲刷新問題,只是一些額外的配置隨着 springboot 的版本不同需要添加配置文件(RedisConfig.java類)進行重寫
公共配置:
RedisConfig.java 類
@Configuration public class RedisConfig { /** * jedis pool springboot2.x.x 獲取pool的工具類 * @param redisProperties * @return */ public JedisPoolConfig getGenericObjectJedisPoolConfig(RedisProperties redisProperties){ //JedisPoolConfig 繼承 GenericObjectPoolConfig類,並將testWhileIdle設置為true JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(redisProperties.getJedis().getPool().getMaxIdle()); jedisPoolConfig.setMinIdle(redisProperties.getJedis().getPool().getMinIdle()); jedisPoolConfig.setMaxTotal(redisProperties.getJedis().getPool().getMaxActive()); jedisPoolConfig.setMaxWaitMillis(redisProperties.getJedis().getPool().getMaxWait().toMillis()); //此處可以設置testOnBorrow,默認值為false,網絡良好的情況下建議使用默認值 return jedisPoolConfig; } /** * 自定義序列化方式 */ @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 使用Jackson2JsonRedisSerialize 替換默認序列化 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); // 初始化string的序列化方式 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 redisTemplate.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 redisTemplate.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson redisTemplate.setValueSerializer(stringRedisSerializer); // hash的value序列化方式采用jackson redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
application.yml
#----------------------------------------springboot2.x.x jedis配置------------------------------------- spring: redis: # host: 127.0.0.1 # port: 6379 clientName: AppName #springboot2.1.x版本沒有此配置需要再RedisConfig.java類中重新寫入 cluster: nodes: 127.0.0.1:6379,127.0.0.2:6379,127.0.0.3:6379,127.0.0.4:6379,127.0.0.5:6379,127.0.0.6:6379 max-redirects: 3 password: 123456 timeout: 50000 ssl: false database: 0 jedis: pool: max-active: 10 max-idle: 8 min-idle: 1 max-wait: 5000
springboot2.3.x-jedis & springboot2.2.x-jedis
RedisConfig.java 類:
@Configuration public class RedisConfig { /** * springboot2.3.x springboot2.2.x 使用 jedis 連接redis單實例或集群,需要添加以下的選項 * 目的:為當前應用添加連接redis的標識,方便多應用連接同一個redis的問題查找 */ @Bean public RedisConnectionFactory connectionFactory(RedisProperties redisProperties) { //添加額外屬性 JedisClientConfiguration clientConfig = JedisClientConfiguration.builder() .clientName(redisProperties.getClientName()) .usePooling().poolConfig(getGenericObjectJedisPoolConfig(redisProperties)).and().readTimeout(redisProperties.getTimeout()) .build(); //單實例連接配置 // RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost()); // configuration.setPort(redisProperties.getPort()); // configuration.setPassword(redisProperties.getPassword()); //集群連接配置 RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes()); configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects()); configuration.setPassword(RedisPassword.of(redisProperties.getPassword())); return new JedisConnectionFactory(configuration, clientConfig); } }
springboot2.1.x-jedis
RedisConfig.java類
@Configuration public class RedisConfig { /** * springboot2.1.x 使用 jedis 連接redis單實例或集群,需要添加以下的選項 * 目的:為當前應用添加連接redis的標識,方便多應用連接同一個redis的問題查找 */ @Bean public RedisConnectionFactory connectionFactory(RedisProperties redisProperties) { //添加額外屬性 JedisClientConfiguration clientConfig = JedisClientConfiguration.builder() //客戶端名稱需要再這里寫死 .clientName("AppName") .usePooling().poolConfig(getGenericObjectJedisPoolConfig(redisProperties)).and().readTimeout(redisProperties.getTimeout()) .build(); //單實例連接配置 // RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost()); // configuration.setPort(redisProperties.getPort()); // configuration.setPassword(redisProperties.getPassword()); //集群連接配置 RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes()); configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects()); configuration.setPassword(RedisPassword.of(redisProperties.getPassword())); return new JedisConnectionFactory(configuration, clientConfig); } }