1、六种淘汰策略

    1. noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
    2. allkeys-lru:在主键空间中,优先移除最近未使用的key。(推荐)
    3. volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key
    4. allkeys-random:在主键空间中,随机移除某个key
    5. volatile-random:在设置了过期时间的键空间中,随机移除某个key
    6. volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
    7. noeviction:当内存使用达到阈值的时候,执行命令直接报错
    8. allkeys-lru:在所有的key中,优先移除最近未使用的key。(推荐)
    9. volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key
    10. allkeys-random:在所有的key中,随机移除某个key
    11. volatile-random:在设置了过期时间的键空间中,随机移除某个key
    12. volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。

    在redis.conf文件中,设置Redis 内存大小的限制,我们可以设置maxmemory ,当数据达到限定大小后,会选择配置的策略淘汰数据
    比如:maxmemory 300mb。
    图片1.png

    通过配置 设置Redis的淘汰策略。比如:maxmemory-policy volatile-lru
    图片2.png

    2、redis中的过期机制

    @Configuration
    public class RedisListenerConfig {
        @Bean
        RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
            RedisMessageListenerContainer container = new RedisMessageListenerContainer();
            container.setConnectionFactory(connectionFactory);
            return container;
        }
    }
    
    @Component
    public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
        public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
            super(listenerContainer);
        }
    
        /**
         * 待支付
         */
        private static final Integer ORDER_STAYPAY = 0;
        /**
         * 失效
         */
        private static final Integer ORDER_INVALID = 2;
        @Autowired
        private OrderMapper orderMapper;
    
        /**
         * Redis失效事件 key
         *
         * @param message
         * @param pattern
         */
        @Override
        public void onMessage(Message message, byte[] pattern) {
            String expiraKey = message.toString();
            // 根据key查询 value 如果还还是为待支付状态 将订单改为已经超时~~
            OrderEntity orderNumber = orderMapper.getOrderNumber(expiraKey);
            System.out.println(expiraKey);
            if (orderNumber == null) {
                return;
            }
            if (orderNumber.getOrderStatus().equals(ORDER_STAYPAY)) {
                // 将订单状态改为已经失效
                orderMapper.updateOrderStatus(expiraKey, ORDER_INVALID);
            }
        }
    }
    

    3、redis中的事物
    Multi开启事务
    EXEC 提交事务
    Watch 可以监听一个或者多个key,在提交事务之前是否有发生了变化如果发生边了变化就不会提交事务,没有发生变化才可以提交事务 版本号码 乐观锁

    watch name
    multi
    set name xiaoxiao
    exec
    

    Discard取消提交事务
    注意:Redis官方是没有提供回滚方法, 值提供了取消事务
    **
    3、布隆过滤器

    缓存穿透
    产生的背景:
    缓存穿透是指使用不存在的key进行大量的高并发查询,导致缓存无法命中,每次请求都要都要穿透到后端数据库查询,使得数据库的压力非常大,甚至导致数据库服务压死;
    解决方案:
        接口层实现api限流、用户授权、id检查等;
        从缓存和数据库都取不到数据的话,一样将数据库空值放入缓存中,设置30s有效期避免使用同一个id对数据库攻击压力大
    
    布隆过滤器适用于判断一个元素在集合中是否存在,但是可能会存在误判的问题。
    实现的原理采用二进制向量数组和随机映射hash函数。
    
    布隆过滤器为什么会产生冲突 ,会根据key计算hash值,可能与布隆过滤器中存放的元素hash产生冲突都是为1,布隆可能会产生误判可能存在。
    如何解决这个问题:二进制数组长度设置比较大,可以减少布隆误判的概率。
    
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>22.0</version>
    </dependency>
    
    @RestController
    public class BlongController {
        @Autowired
        private OrderMapper orderMapper;
        @Autowired
        private RedisTemplateUtils redisTemplateUtils;
    
        BloomFilter<Integer> integerBloomFilter;
    
        @RequestMapping("/getOrder")
        public OrderEntity getOrder(Integer orderId) {
            if (integerBloomFilter != null) {
                if (!integerBloomFilter.mightContain(orderId)) {
                    System.out.println("从布隆过滤器中检测到该key不存在");
                    return null;
                }
            }
    
            // 1.先查询Redis中数据是否存在
            OrderEntity orderRedisEntity = (OrderEntity) redisTemplateUtils.getObject(orderId + "");
            if (orderRedisEntity != null) {
                System.out.println("直接从Redis中返回数据");
                return orderRedisEntity;
            }
            // 2. 查询数据库的内容
            System.out.println("从DB查询数据");
            OrderEntity orderDBEntity = orderMapper.getOrderById(orderId);
            if (orderDBEntity != null) {
                System.out.println("将Db数据放入到Redis中");
                redisTemplateUtils.setObject(orderId + "", orderDBEntity);
            }
            return orderDBEntity;
        }
    
        @RequestMapping("/dbToBulong")
        public String dbToBulong() {
            List<Integer> orderIds = orderMapper.getOrderIds();
            integerBloomFilter = BloomFilter.create(Funnels.integerFunnel(), orderIds.size(), 0.01);
            for (int i = 0; i < orderIds.size(); i++) {
                integerBloomFilter.put(orderIds.get(i));
            }
    
            return "success";
        }
    
    }
    

    Redis基于布隆过滤器解决缓存穿透问题.docx