Redis常见面试题

Redis常见面试题

Redis知识框架:

在这里插入图片描述

1. 缓存穿透

在这里插入图片描述

缓存穿透:去redis查询一个不存在的数据,数据库查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库。

1.1 缓存空数据

缓存空数据,查询返回的数据为空,仍把这个空结果进行缓存;

优点:简单;

缺点:消耗内存,可能会导致数据不一致的问题;

1.2 布隆过滤器

布隆过滤器,当一个查询请求过来时,先经过布隆过滤器进行判断,如果判断请求查询值存在,则继续查;如果判断请求查询不存在,直接丢弃;

优点:内存占用较少,没有多余key;

缺点:实现复杂,可能存在误判

布隆过滤器底层是bitmap(位图):相当于是一个以(bit)位为单位的数组,数组中每个单元只能存储二进制数0或1

布隆过滤器作用布隆过滤器可以用于检索一个元素是否在一个集合中

误判率:数组越小误判率就越大,数组越大误判率就越小,但是同时带来了更多的内存消耗。

在这里插入图片描述

在这里插入图片描述

应用Redis的布隆过滤器:

    /**
     * 根据主键id查询
     * Cacheable注解是spring缓存注解,在方法执行前 Spring 会先查看缓存中是否有key,如果有key,则直接返回缓存数据;
     * 若没有key,调用方法并将方法返回值放到缓存中。
     * condition设置当查询结果不为null时生效;
     * cacheNames设置默认前缀,完整key为article:id
     *
     * @param id 主键id
     * @return 文章实体
     */
    @Cacheable(cacheNames = "article", key = "#id", condition = "#result!=null")
    @Override
    public Article getById(Long id) {
   
        // bloomFilter中不存在该key,为非法访问
        if (!bloomFilter.contains(id)) {
   
            /**
             * condition = "#result!=null"并在非法访问的时候返回null的目的是不将该次查询返回的null使用
             * 所以我们需要在缓存中添加一个可容忍的短期过期的null或者是其它自定义的值,使得短时间内直接读取缓存中的该值。
             */
            long ttl = new Random().nextInt(500) + 1000;    // 随机过期时间
            Article article = new Article();
            stringRedisTemplate.opsForValue().set("article:" + id, JSONUtil.toJsonStr(article), ttl, TimeUnit.SECONDS);
            return null;
        }
        // 不是非法访问,可以访问mysql数据库
        Article article = this.lambdaQuery().eq(Article::getId, id).one();
        return article;
    }

以下为测试Redisson的布隆过滤器代码:

package com.example.redisson;

import com.example.redisson.domain.po.Article;
import com.example.redisson.service.IArticleService;
import com.example.redisson.util.BloomFilterUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest(classes = RedissonDemoApplication.class)
@Slf4j
class RedissonDemoApplicationTests {
   

    static long expectedInsertions = 2000L;    // 预期插入数量
    static double falseProbability = 0.01;  // 误判率
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private BloomFilterUtil bloomFilterUtil;
    @Autowired
    private IArticleService articleService;
    private RBloomFilter<Long> bloomFilter = null;


    /**
     * 初始化布隆过滤器
     */
    public void init() {
   
        log.info("开始初始化布隆过滤器...");
        // 查询数据库,用于启动项目时初始化bloomFilter
        List<Article> articleList = articleService.list();
        // 创建布隆过滤器,参数依次为:过滤器名称、预测插入数量和误判率
        bloomFilter = bloomFilterUtil.create("idBloomFilter", expectedInsertions, falseProbability);
        for (Article article : articleList) {
   
            bloomFilter.add(article.getId());
        }
        log.info("初始化布隆过滤器完成...");
    }

    @Test
    void test() {
   
        init(); // 初始化布隆过滤器
        long count = 0;
        long totalChecks = 2000; // 测试数据共2000个,1000真1000假,计算误判率

        // 测试数据id从1-1000是真实存在的,会初始化到布隆过滤器;id大于1000不存在,检测误判率
        for (long i = 1; i <= totalChecks; i++) {
   
            if ((i <= 1000 && !bloomFilter.contains(i))
                    || (i > 1000 && bloomFilter.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值