赢展网站建设,网站域名需icp备案,wordpress主题正版,响应式网站建设策划redis搭建集群模式、Cluster模式#xff08;6节点#xff0c;3主3从集群模式#xff0c;添加删除节点#xff09;_redis cluster节点带数据增减-CSDN博客 Linux部署Redis哨兵集群 一主两从三哨兵#xff08;这里使用Redis6#xff0c;其它版本类似#xff09;_linux red…redis搭建集群模式、Cluster模式6节点3主3从集群模式添加删除节点_redis cluster节点带数据增减-CSDN博客 Linux部署Redis哨兵集群 一主两从三哨兵这里使用Redis6其它版本类似_linux redis集群模式部署-CSDN博客
配置yaml
redis:redis-configs:redis-order:type: sentinel #standalone clusterhostAndPort: 192.168.132.1:16379,192.168.132.1:16380,192.168.132.1:16381masterName: mymasterpassword: dyj1username:database: 15timeout: 10000pool:max-idle: 8min-idle: 0max-active: 8max-wait: 10000
# redis-pay:
# type: standalone
# hostAndPort: localhost:6380
# database: 14
# timeout: 10000
# pool:
# max-idle: 8 # 连接池中的最大空闲连接 默认 8
# min-idle: 0 # 连接池中的最小空闲连接 默认 0
# max-active: 8 # 连接池最大连接数使用负值表示没有限制 默认 8
# max-wait: 10000 # 连接池最大阻塞等待时间使用负值表示没有限制 默认 -1
# redis-order-cluster:
# type: cluster
# hostAndPort: xxx:6379,xxx:6379,xxx:6379
# database: 15
# timeout: 10000
# max-redirects: 3
# pool:
# max-idle: 8
# min-idle: 0
# max-active: 8
# max-wait: 10000
# redis-pay-cluster:
# type: cluster
# hostAndPort: xxx:6379,xxx:6379,xxx:6379
# database: 14
# timeout: 10000
# pool:
# max-idle: 8
# min-idle: 0
# max-active: 8
# max-wait: 10000
cache:caffeine:cache10M: initialCapacity20,maximumSize100,expireAfterWrite10m,recordStatscache30s: initialCapacity20,maximumSize100,expireAfterWrite30sredis:cache10M: 10cache30s: 30
redis连接池
package org.example.redis.config;import freemarker.template.utility.StringUtil;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnection;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.util.Pair;import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.*;Configuration
Data
EnableConfigurationProperties({RedisPoolConfig.class})
public class RedisConnectionFactoryConfig {public static MapString, LettuceConnectionFactory redisConnectionFactors new HashMap();Autowiredprivate RedisPoolConfig redisPoolConfig;PostConstructpublic void init() {redisPoolConfig.getRedisConfigs().forEach((name, config) - {LettuceConnectionFactory redisConnectionFactory null;LettuceClientConfiguration clientConfig getClientConfiguration(config);switch (config.getType()) {case standalone:RedisStandaloneConfiguration redisStandaloneConfiguration createRedisStandaloneConfiguration(config);if (redisStandaloneConfiguration ! null) {redisConnectionFactory new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);}break;case cluster:RedisClusterConfiguration redisClusterConfiguration createRedisClusterConfiguration(config);if (redisClusterConfiguration ! null) {redisConnectionFactory new LettuceConnectionFactory(redisClusterConfiguration, clientConfig);}break;case sentinel:RedisSentinelConfiguration redisSentinelConfiguration createRedisSentinelConfiguration(config);if (redisSentinelConfiguration ! null) {redisConnectionFactory new LettuceConnectionFactory(redisSentinelConfiguration, clientConfig);}break;default:System.out.printf(Unknown type: %d\n, config.getType());break;}if (null ! redisConnectionFactory) {// 在获取连接时先验证连接是否已经中断如果已经中断则创建一个新的连接redisConnectionFactory.setValidateConnection(true);redisConnectionFactory.afterPropertiesSet(); // start() for spring-data-redis-3.X; afterPropertiesSet() for spring-data-redis-2.XredisConnectionFactors.putIfAbsent(name, redisConnectionFactory);}});}private LettuceClientConfiguration getClientConfiguration(RedisPoolConfig.Config config) {GenericObjectPoolConfigLettuceConnection poolConfig new GenericObjectPoolConfig();if (StringUtils.isNotBlank(config.getPool().getMaxActive())) {poolConfig.setMaxTotal(Integer.parseInt(config.getPool().getMaxActive()));}if (StringUtils.isNotBlank(config.getPool().getMaxWait())) {poolConfig.setMaxWait(Duration.ofMillis(Integer.parseInt(config.getPool().getMaxWait())));}if (StringUtils.isNotBlank(config.getPool().getMaxIdle())) {poolConfig.setMaxIdle(Integer.parseInt(config.getPool().getMaxIdle()));}if (StringUtils.isNotBlank(config.getPool().getMinIdle())) {poolConfig.setMinIdle(Integer.parseInt(config.getPool().getMinIdle()));}int timeout -1;if (StringUtils.isNotBlank(config.getTimeout())) {timeout Integer.parseInt(config.getTimeout());}if (StringUtils.equals(config.getType(), cluster)){// 支持自适应集群拓扑刷新和动态刷新源ClusterTopologyRefreshOptions clusterTopologyRefreshOptions ClusterTopologyRefreshOptions.builder().enableAllAdaptiveRefreshTriggers()// 开启自适应刷新.enableAdaptiveRefreshTrigger()// 开启定时刷新 default 60 SECONDS.enablePeriodicRefresh(Duration.ofSeconds(5)).build();ClusterClientOptions clusterClientOptions ClusterClientOptions.builder().topologyRefreshOptions(clusterTopologyRefreshOptions)// RedisTemplate通过StatefulRedisClusterConnection发送GET命令到Redis集群。// 根据Redis集群的哈希槽机制命令被路由到正确的节点。// 如果键不存在于当前节点会触发重定向最多max-redirects次直到找到正确的节点或者达到最大重定向次数。//.maxRedirects().build();LettuceClientConfiguration lettuceClientConfiguration LettucePoolingClientConfiguration.builder().poolConfig(poolConfig)//.readFrom(ReadFrom.SLAVE_PREFERRED) //读写分离主写从读模式配置.clientOptions(clusterClientOptions).build();return lettuceClientConfiguration;}LettuceClientConfiguration clientConfig LettucePoolingClientConfiguration.builder().shutdownTimeout(Duration.ofMillis(timeout)).poolConfig(poolConfig).build();return clientConfig;}private RedisSentinelConfiguration createRedisSentinelConfiguration(RedisPoolConfig.Config config) {RedisSentinelConfiguration redisSentinelConfiguration new RedisSentinelConfiguration();redisSentinelConfiguration.setMaster(config.getMasterName());ListPairString, Integer hostAndPorts parseClusterHostAndPort(config.getHostAndPort());if (hostAndPorts.isEmpty()) {return null;}for (PairString, Integer hostAndPort : hostAndPorts) {RedisNode.RedisNodeBuilder builder RedisNode.newRedisNode()
// .promotedAs(RedisNode.NodeType.SLAVE).listeningAt(hostAndPort.getFirst(), hostAndPort.getSecond());redisSentinelConfiguration.addSentinel(builder.build());}setUsername(config, redisSentinelConfiguration);setPassword(config, redisSentinelConfiguration);setDatabase(config, redisSentinelConfiguration);return redisSentinelConfiguration;}private RedisClusterConfiguration createRedisClusterConfiguration(RedisPoolConfig.Config config) {ListPairString, Integer hostAndPorts parseClusterHostAndPort(config.getHostAndPort());if (hostAndPorts.isEmpty()) {return null;}RedisClusterConfiguration redisClusterConfiguration new RedisClusterConfiguration();for (PairString, Integer hostAndPort : hostAndPorts) {RedisNode node new RedisNode(hostAndPort.getFirst(), hostAndPort.getSecond());redisClusterConfiguration.addClusterNode(node);}setUsername(config, redisClusterConfiguration);setPassword(config, redisClusterConfiguration);setClusterConf(config, redisClusterConfiguration);return redisClusterConfiguration;}private RedisStandaloneConfiguration createRedisStandaloneConfiguration(RedisPoolConfig.Config config) {PairString, Integer hostAndPort parseHostAndPort(config.getHostAndPort());if (null hostAndPort) {return null;}RedisStandaloneConfiguration redisStandaloneConfiguration new RedisStandaloneConfiguration();redisStandaloneConfiguration.setHostName(hostAndPort.getFirst());redisStandaloneConfiguration.setPort(hostAndPort.getSecond());setUsername(config, redisStandaloneConfiguration);setPassword(config, redisStandaloneConfiguration);setDatabase(config, redisStandaloneConfiguration);return redisStandaloneConfiguration;}private void setUsername(RedisPoolConfig.Config config, RedisConfiguration.WithPassword connectionFactory) {if (null ! config.getUsername() !config.getUsername().isEmpty()) {connectionFactory.setUsername(config.getUsername());}}private void setPassword(RedisPoolConfig.Config config, RedisConfiguration.WithPassword connectionFactory) {if (null ! config.getPassword() !config.getPassword().isEmpty()) {connectionFactory.setPassword(config.getPassword());}}private void setDatabase(RedisPoolConfig.Config config, RedisConfiguration.WithDatabaseIndex connectionFactory) {if (null ! config.getDatabase() !config.getDatabase().isEmpty()) {int database Integer.parseInt(config.getDatabase());connectionFactory.setDatabase(database);}}private void setClusterConf(RedisPoolConfig.Config config, RedisClusterConfiguration redisClusterConfiguration) {if (null ! config.getClusterMaxRedirects() !config.getClusterMaxRedirects().isEmpty()) {int maxRedirects Integer.parseInt(config.getClusterMaxRedirects());redisClusterConfiguration.setMaxRedirects(maxRedirects);}}private ListPairString, Integer parseClusterHostAndPort(String hostAndPortStr) {String[] hosts hostAndPortStr.split(,);ListPairString, Integer hostAndPorts new ArrayList();for (String hostAndPort : hosts) {PairString, Integer pair parseHostAndPort(hostAndPort);if (null ! pair) {hostAndPorts.add(pair);}}return hostAndPorts;}private PairString, Integer parseHostAndPort(String hostAndPortStr) {String[] hostAndPort hostAndPortStr.split(:);if (hostAndPort.length ! 2) {System.out.printf(Invalid host and port: %s\n, hostAndPortStr);return null;}String host hostAndPort[0].trim();String port hostAndPort[1].trim();return Pair.of(host, Integer.parseInt(port));}
}缓存管理类
package org.example.redis.config;import com.github.benmanes.caffeine.cache.*;
import lombok.extern.slf4j.Slf4j;
import org.example.redis.listener.CaffeineCacheRemovalListener;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;import javax.annotation.Resource;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;Slf4j
Configuration
EnableCaching
EnableConfigurationProperties({CustomerCacheProperties.class})
public class CacheManagerConfiguration {public interface redisCacheKey {public final static String cache10M cache10M;public final static String cache30s cache30s;}public interface caffeineCacheKey {public final static String cache10M cache10M;public final static String cache30s cache30s;}Resourceprivate CustomerCacheProperties customerCacheProperties;public interface CacheManagerNames {String REDIS_CACHE_MANAGER redisCacheManager;String LOCAL_CACHE_MANAGER localCacheManager;}Bean(name CacheManagerNames.REDIS_CACHE_MANAGER)Primarypublic RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {MapString, RedisCacheConfiguration expires new HashMap();customerCacheProperties.getRedis().forEach((name, time) - {expires.put(name, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(Integer.parseInt(time))));});// MapString, RedisCacheConfiguration expires ImmutableMap.String, RedisCacheConfigurationbuilder()
// .put(cache15, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(15)))
// .put(cache30, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(30)))
// .build();RedisCacheManager redisCacheManager RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(factory).cacheDefaults(cacheConfiguration()).withInitialCacheConfigurations(expires)//事务感知功能有助于确保在事务提交之后缓存和数据库中的数据保持一致这对于保证数据完整性和避免脏读非常重要。// 然而这也可能会增加一些性能开销因此在不需要强一致性的场景下可以考虑禁用这个特性以提高性能.transactionAware().build();//以锁写入的方式创建RedisCacheWriter对象
// RedisCacheWriter writer RedisCacheWriter.lockingRedisCacheWriter(factory);return redisCacheManager;}Beanpublic RedisCacheConfiguration cacheConfiguration() {return RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));}Bean(name CacheManagerNames.LOCAL_CACHE_MANAGER)public CacheManager caffeineCacheManager() {ListCaffeineCache caffeineCaches new ArrayList();customerCacheProperties.getCaffeine().forEach((name, spec) - {CaffeineSpec caffeineSpec CaffeineSpec.parse(spec);CaffeineObject, Object caffeine Caffeine.from(caffeineSpec);caffeine.removalListener(new CaffeineCacheRemovalListener());// caffeineCache.executor(cacheExecutor);// 设置定时任务执行过期清除操作//.scheduler(Scheduler.systemScheduler())//cache对缓存写的通知回调caffeine.writer(new CacheWriterObject, Object() {Overridepublic void write(Object key, Object value) {log.info(CacheManager write key{}, key);}Overridepublic void delete(Object key, Object value, RemovalCause cause) {log.info(CacheManager delete key{}, cause{}, key, cause);}});// //使用CacheLoader创建一个LoadingCache
// caffeine.build(new CacheLoaderString, String() {
// //同步加载数据
// Override
// public String load(String key) throws Exception {
// log.info(CacheManager load key{}, key);
// return value_ key;
// }
//
// //异步加载数据
// Override
// public String reload(String key, String oldValue) throws Exception {
// log.info(CacheManager reload key{}, key);
// return value_ key;
// }
// });CaffeineCache caffeineCache new CaffeineCache(name, caffeine.build());caffeineCaches.add(caffeineCache);});SimpleCacheManager simpleCacheManager new SimpleCacheManager();simpleCacheManager.setCaches(caffeineCaches);return simpleCacheManager;}// Override
// Cacheable(key #userId, cacheNames CacheManagerConfiguration.CacheNames.CACHE_15MINS,
// cacheManager CacheManagerConfiguration.CacheManagerNames.EHCACHE_CACHE_MANAGER)
// public User findUserAccordingToId(Long userId) {
// return userRepository.findById(userId).orElse(User.builder().build());
// }
//
// Override
// Cacheable(key #username, cacheNames CacheManagerConfiguration.CacheNames.CACHE_15MINS,
// cacheManager CacheManagerConfiguration.CacheManagerNames.REDIS_CACHE_MANAGER)
// public User findUserAccordingToUserName(String username) {
// return userRepository.findUserByUsername(username);
// }// Cacheable( sync true)} 创建不同的template
package org.example.redis.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import static org.example.redis.config.RedisConnectionFactoryConfig.redisConnectionFactors;Configuration
Data
DependsOn(redisConnectionFactoryConfig)
public class RestTemplateConfig {Bean(name orderStringRedisTemplate)Primarypublic StringRedisTemplate orderStringRedisTemplate() {return buildStringRedisTemplate(redisConnectionFactors.get(redis-order));}//
// public RedisTemplateString, Object buildObjRedisTemplate(RedisConnectionFactory factory) {
//
// RedisTemplateString, Object redisTemplate new RedisTemplate();
// redisTemplate.setConnectionFactory(factory);
//
// Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer jackson2JsonRedisSerializer();
// redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// redisTemplate.setKeySerializer(new StringRedisSerializer());
//
// redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
// redisTemplate.afterPropertiesSet();
// return redisTemplate;
// }public StringRedisTemplate buildStringRedisTemplate(RedisConnectionFactory factory) {StringRedisTemplate redisTemplate new StringRedisTemplate(factory);Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer jackson2JsonRedisSerializer();redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}private Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer() {Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om new ObjectMapper();// 指定要序列化的域field,get和set,以及修饰符范围ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型类必须是非final修饰的final修饰的类比如String,Integer等会跑出异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);return jackson2JsonRedisSerializer;}}使用实体类接收使用Map接收。key需要根据自己的业务区分即可
package org.example.redis.config;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Map;Data
NoArgsConstructor
AllArgsConstructor
Component
ConfigurationProperties(prefix redis)
public class RedisPoolConfig {public MapString, Config redisConfigs;NoArgsConstructorAllArgsConstructorDatapublic static class Config {private String name;private String type;private String hostAndPort;private String username;private String password;private String database;
// private String sentinelMasterHostAndPort; // for Sentineprivate String masterName; // for Sentineprivate String clusterMaxRedirects; // for Clusterprivate String timeout;private PoolConfig pool;DataNoArgsConstructorAllArgsConstructorpublic static class PoolConfig {private String maxIdle;private String minIdle;private String maxActive;private String maxWait;}}
}
缓存redis 以及caffeine
package org.example.redis.config;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Map;Data
NoArgsConstructor
AllArgsConstructor
Component
ConfigurationProperties(prefix cache)
public class CustomerCacheProperties {public MapString, String caffeine;public MapString, String redis;
}!-- lettuce这个客户端--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId
/dependency dependencygroupIdcom.github.ben-manes.caffeine/groupIdartifactIdcaffeine/artifactIdversion2.9.3/version
/dependency