redis、术语方案、Lettuce、cache.spring

 

1,缓存击穿是指当缓存中的某个热点数据过期时,大量的查询请求会直接穿透缓存查询数据库,导致数据库压力骤增,可能引发服务故障
   互斥锁解决
2,缓存穿透,如果查询一个不存在的数据,数据库查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库,相当于缓存失效
   布隆过滤器解决
3,缓存雪崩:Redis中缓存的数据大面积同时失效,或者Redis宕机,从而会导致大量请求直接到数据库,压垮数据库
   设置有效期均匀分布 数据预热
布隆过滤器: 请求到达缓存前先在布隆过滤器预检查,如果布隆过滤器判断该键可能不存在,则直接返回请求不存在的结果,不再进行后续的缓存和数据库查询。如果布隆过滤器判断该键可能存在,则继续进行后续操作
用于快速判断一个元素是否属于一个集合。它以较小的空间占用和高效的查询时间著称
Bloom 过滤器基于哈希函数和位数组实现。它的核心思想是使用多个哈希函数将元素映射到位数组中,并将对应的位设置为1。当查询一个元素时,通过对该元素进行相同的哈希计算,检查对应的位是否都为1。如果其中有任何一位为0,则可以确定该元素不在集合中;如果所有位都为1,则该元素可能在集合中,但并不确定,存在一定的概率误判。

  

Lettuce
   @Value("${spring.redis-sentinel.nodes}")
    private String redisNodes; //192.xx.66:26379,192.xx.65:26379,192.xx.64:26379
    @Value("${spring.redis-sentinel.master}")
    private String master;
    @Value("${spring.redis-sentinel.password}")
    private String sentinelPassword;
    @Value("${spring.redis-sentinel.database}")
    private int sentinelDatabase ;
    @Bean(name = "redisSentinelConfiguration")
    public RedisSentinelConfiguration redisSentinelConfiguration(){
        RedisSentinelConfiguration configuration = new RedisSentinelConfiguration();
        String[] host = redisNodes.split(",");
        for(String redisHost : host){
            String[] item = redisHost.split(":");
            String ip = item[0];
            String port = item[1];
            configuration.addSentinel(new RedisNode(ip, Integer.parseInt(port)));
        }
        configuration.setMaster(master);
        configuration.setDatabase(sentinelDatabase);
        configuration.setPassword(sentinelPassword);
        return configuration;
    }

    @Bean(name = "sentinelLettuceConnectionFactory")
    public LettuceConnectionFactory sentinelLettuceConnectionFactory(RedisSentinelConfiguration redisSentinelConfiguration) {
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisSentinelConfiguration);
        return lettuceConnectionFactory;
    }

    @Primary
    @Bean("lettuceConnectionFactory")
    public LettuceConnectionFactory lettuceConnectionFactory(){
        //redis配置
        RedisConfiguration redisConfiguration = new RedisStandaloneConfiguration(host,port);
        ((RedisStandaloneConfiguration) redisConfiguration).setDatabase(database);
        ((RedisStandaloneConfiguration) redisConfiguration).setPassword(password);

        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisConfiguration);
        return lettuceConnectionFactory;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisConnectionFactory redisConnectionFactory = (RedisConnectionFactory) applicationContext.getBean(RedisModeEnum.getValueByCode(redisMode));
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

public enum RedisModeEnum {
    sentinel("sentinel","sentinelLettuceConnectionFactory"),standalone("standalone","lettuceConnectionFactory");

 

 

jedis连接池JedisPoolConfig配置
https://blog.csdn.net/u011271894/article/details/120787584
   @Value("${spring.redis.host}")
    private String host ;
    @Value("${spring.redis.port}")
    private String port ;
    @Value("${spring.redis.password}")
    private String password ;
    @Value("${spring.redis.database}")
    private String database ;

    @Bean(name = "jedisConnectionFactory")
    public JedisConnectionFactory jedisConnectionFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(8);//资源池中的最大连接数 default 8
        jedisPoolConfig.setMaxIdle(8);//资源池允许的最大空闲连接数 default 8
        jedisPoolConfig.setMinIdle(0);//资源池确保的最少空闲连接数 default 0
        jedisPoolConfig.setMaxWaitMillis(-1);//当资源池连接用尽后,调用者的最大等待时间 默认-1不超时

        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(Integer.parseInt(port));
        redisStandaloneConfiguration.setPassword(password);
        redisStandaloneConfiguration.setDatabase(Integer.parseInt(database));

        JedisClientConfiguration.JedisClientConfigurationBuilder configurationBuilder = JedisClientConfiguration.builder();
        JedisClientConfiguration jedisClientConfiguration = configurationBuilder.usePooling().poolConfig(jedisPoolConfig).build();

        return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {//RedisConnectionFactory redisConnectionFactory
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory);

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.6.8</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.6.8</version>
        </dependency>

 

 

 

cacheNames 与 @Cacheable(value = "user" 效果一致
类修饰 @CacheConfig(cacheNames = "xingMhqqqq")

@Cacheable(cacheNames = "xingMh2",key ="#name")// 方法上有cacheNames 覆盖类上的
public String xmhTest(String name) {
System.out.println("****************111111:"+name);
return "sysDicsXingmhvaluess";
}

  

@EnableCaching 开启cache管理

//设置RedisCacheManager
//使用cache注解管理redis缓存
@Bean
public CacheManager cacheManager(@Qualifier("jedisConnectionFactory") JedisConnectionFactory jedisConnectionFactory) {
	RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
	defaultCacheConfig=defaultCacheConfig.entryTtl(Duration.ofHours(-1))
// 设置 key为string序列化
			.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
// 设置value为json序列化
			.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
// 不缓存空值
			.disableCachingNullValues();
// 对每个缓存空间应用不同的配置
// Set<String> cacheNames = new HashSet<>();
// cacheNames.add(userCacheName);
// Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
// configMap.put(userCacheName, defaultCacheConfig.entryTtl(Duration.ofSeconds(userCacheExpireTime)));

	RedisCacheManager cacheManager = RedisCacheManager.builder(jedisConnectionFactory)
			.cacheDefaults(defaultCacheConfig)
// .initialCacheNames(cacheNames)
// .withInitialCacheConfigurations(configMap)
			.build();
	return cacheManager;
}

@Cacheable(value = "getCacheableTestxxxxx",key = "#code",unless="#result == null")
public String getCacheableTest(String code){
	System.out.println("**********getCacheableTest");
	return "getCacheableTest-value";
}

	样例: getCacheableTestxxxxx::xing

  

 

        org.springframework.cache.annotation.Cacheable
	org.springframework.cache.CacheManager 使用cache注解管理redis缓存 mapi
	org.springframework.data.redis.cache.RedisCacheManager 实现了 CacheManager
	https://www.cnblogs.com/junzi2099/p/8301796.html

	根据运行流程,如下@Cacheable将在执行方法之前( #result还拿不到返回值)判断condition,如果返回true,则查缓存;
	@Cacheable(value = "user", key = "#id", condition = "#id lt 10")
	public User conditionFindById(final Long id)

	如下@CachePut将在执行完方法后(#result就能拿到返回值了)判断condition,如果返回true,则放入缓存
	@CachePut(value = "user", key = "#id", condition = "#result.username ne 'zhang'")
	public User conditionSave(final User user)

	如下@CachePut将在执行完方法后(#result就能拿到返回值了)判断unless,如果返回false,则放入缓存;(即跟condition相反)
	@CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'")
	public User conditionSave2(final User user)

	如下@CacheEvict, beforeInvocation=false表示在方法执行之后调用(#result能拿到返回值了);且判断condition,如果返回true,则移除缓存;
	@CacheEvict(value = "user", key = "#user.id", beforeInvocation = false, condition = "#result.username ne 'zhang'")

	@Cacheable(value="accountCache",key="#accountName.concat(#password)")
	通过少量的配置 annotation 凝视就可以使得既有代码支持缓存
	支持开箱即用 Out-Of-The-Box,即不用安装和部署额外第三方组件就可以使用缓存
	支持 Spring Express Language,SpEL表达式,能使用对象的不论什么属性或者方法来定义缓存的 key 和 condition
	支持 AspectJ,并通过事实上现不论什么方法的缓存支持
	支持自己定义 key 和自己定义缓存管理者,具有相当的灵活性和扩展性

/**
 * 基于SpringBoot2 对 RedisCacheManager 的自定义配置
 * @param redisConnectionFactory
 * @return
 */
	@Bean
	public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//初始化一个RedisCacheWriter
		RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
//设置CacheManager的值序列化方式为json序列化
		RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();
		RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer);
		RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);

//设置默认超过时期是1天
		defaultCacheConfig.entryTtl(Duration.ofDays(1));
//初始化RedisCacheManager
		return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
	}

  https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#redis:sentinel

 

 @Bean
    @ConditionalOnMissingBean(CacheManager.class)
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(PropertiesUtil.getInt("redis.cache.ttl", 10)));
        RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(configuration);
        if (new Boolean(PropertiesUtil.getString("redis.cache.enableTransaction"))) {
            builder.transactionAware();
        }
        RedisCacheManager cacheManager = builder.build();
        return cacheManager;
    }

  

 

posted @ 2021-07-03 17:09  XUMT111  阅读(64)  评论(0)    收藏  举报