学会布隆过滤器,能当CEO?

263 阅读4分钟

前言

我们前两天讲了布隆过滤器的底层原理和用途,有小伙伴表示没听爽。那老哥只能再来一次了,谁让我是你们的老哥呢。(默默感动就好)

这篇文章我们主要讲布隆过滤器的使用,比如缓存雪崩视频推送等案例来讲解。如果对布隆过滤器原理不熟悉的小伙伴,可以去历史文章里读一下之前的文章。

Redis缓存穿透解决案例

其实布隆过滤器本质来讲,就是起到一个黑名单或者白名单的作用。我们从这两个角度去分析缓存穿透问题。

白名单解决缓存穿透

注意问题

  • 如果没在白名单里的数据被误判存在于过滤器里的话,会穿透到数据库,不过误判的几率本来就很小,所以穿透问题不大。
  • 必须将所有的查询key都放到布隆过滤器和Redis里,否则请求会被直接返回空数据。

代码实现

老哥按照这个流程图给大家一份代码,其他几种情况,大家思考怎么去实现。

pom

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.13.4</version>
</dependency>

Java代码

import com.alibaba.fastjson.JSON;
import com.bilibili.itlaoge.model.User;
import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

/**
 * 解决缓存穿透—白名单
 */
public class RedissonBloomFilter {

    /**
     * 构造Redisson
     */
    static RedissonClient redisson = null;

    static RBloomFilter<String> bloomFilter = null;

    static {
      Config config = new Config();
      config.useSingleServer().setAddress("redis://127.0.0.1:6379");

      //构造Redisson
      redisson = Redisson.create(config);
      //构造布隆过滤器
      bloomFilter = redisson.getBloomFilter("userIdFilter");

      // 将查询数据放入Redis缓存和布隆过滤器里
      initData(redisson, bloomFilter);
  }
  
  private static void initData(RedissonClient redisson, RBloomFilter<String> bloomFilter) {

      //初始化布隆过滤器:预计元素为100000000L,误差率为3%
      bloomFilter.tryInit(100000000L,0.01);

      //将id为1的数据,插入到布隆过滤器中
      bloomFilter.add("1");
      bloomFilter.add("2");

      // 将id为1对应的user数据,插入到Redis缓存中
      redisson.getBucket("1").set("{id:1, userName:'张三', age:18}");
    }

    public static void main(String[] args) {

      User user = getUserById(2L);
      System.out.println("user对象为:" + JSON.toJSONString(user));
    }

    public static User getUserById(Long id) {

      if (null == id) {
          return null;
      }
      String idKey = id.toString();

      // 开始模拟缓存穿透
      // 前端查询请求key
      if (bloomFilter.contains(idKey)) {

          // 通过了过滤器白名单校验,去Redis里查询真正的数据
          RBucket<Object> bucket = redisson.getBucket(idKey);
          Object object = bucket.get();

          // 如果Redis有数据,直接返回该数据
          if (null != object) {
              System.out.println("从Redis里面查询出来的");
              String userStr = object.toString();
              return JSON.parseObject(userStr, User.class);
          }

          // 如果Redis为空,去查询数据库
          User user = selectByDb(idKey);
          if (null == user) {
              return null;
          } else {
              // 将数据重新刷进缓存
              redisson.getBucket(id.toString()).set(JSON.toJSONString(user));
          }
          return user;
      }

      return null;
    }

    private static User selectByDb(String id) {
      System.out.println("从MySQL里面查询出来的");
      User user = new User();
      user.setId(1L);
      user.setUserName("张三");
      user.setAge(18);
      return user;
    }

}

user对象

/**
 * 用户实体类
 * @author hp
 */
public class User implements Serializable {

    public static String maYunPhone = "18890019390";

    private Long id;

    /**
     * 用户名
     */
    private String userName;

    /**
     * 年龄
     */
    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

}

黑名单解决缓存穿透

注意问题

  • 布隆过滤器里的数据,存在误判,如果正常数据被误判存在黑名单里的话,会直接返回空数据。
  • 黑名单里的数据要很全面才行,否则会有比较严重的穿透问题。
  • 本来是在黑名单里的非法数据,之后有可能是正常数据。如:用id大于100万的数来请求,我们数据库里只有10万数据,这时候如果把id放进黑名单里。等数据达到100万的时候,就会出现问题。

思考题

如果黑名单的方式和白名单的方式结合起来,大家知道怎么去使用吗?希望大家能多去思考一下。

应用场景再举例

以下场景仅是举例,不涉及具体业务实现。目的是让大家更好的明白布隆过滤器,作为黑名单和白名单的使用。

视频推送场景(黑名单)

背景:某视频网站给用户推送视频

布隆过滤器作用:当黑名单使用。

要求:对于某用户,已经推送过的视频,不在进行推送。

流程:当推送给用户一批视频时,先判断这些视频是否存在过滤器里;如果存在不推送给用户,不存在推送给用户;同时将推送过的视频存入过滤器黑名单里,防止下次重复推送。

转载视频/文章案例(白名单)

背景:某用户想转载老哥的文章。

布隆过滤器作用:当白名单使用。

要求:在老哥转发白名单里的,有转发文章的权限。

流程:某用户想转发老哥的文章,由于没在白名单里,转发失败。于是找到老哥开白名单,老哥把他加入了白名单里后,允许转发了。

结语

没有完美的技术,每个技术都有优缺点。一项技术不可能适用于所有业务,我们要做的是扬长避短,利用技术的优点去实现我们的业务需求。

就像我们每个人都有优点和缺点,我们要挖掘我们的长处,去做适合我们的事情。

就好比让我去当CEO,CEO来给我写代码,虽然心里很爽啊,但是估计过不了多久,公司就黄了。