Redis 为什么使用跳表而不是 B+ 树?

  1. B+树很耗费空间,而内存的空间是很宝贵的,相比之下跳表这种可控参数更合适
  2. B+树的范围查询,通过跳表也可以实现
  3. B+树在并发编程下的锁粒度更大
  4. B+树比跳表更难维护和利用

Java 的类加载机制

  1. 加载 (Loading): 通过全限定名获取二进制字节流,在内存中生成 java.lang.Class 对象。
  2. 链接 (Linking):
    • 验证: 确保字节码符合 JVM 规范,没有安全风险。
    • 准备:静态变量分配内存并设置初始默认值(如 int0)。注意:此时还没执行赋值动作。
    • 解析: 将符号引用替换为直接引用(内存地址)。
  3. 初始化 (Initialization): 执行类构造器 <clinit>() 方法的过程,真正执行静态变量赋值和 static 代码块。
  4. 使用 (Using): 程序执行业务逻辑。
  5. 卸载 (Unloading): 类从方法区移除(条件非常苛刻)。

类什么时候会被卸载

  1. 无任何实例对象:该类及其子类在堆中没有任何实例对象
  2. 类加载器回收:根据双亲委派模型,由于系统类加载器几乎不会被回收,只要是自己创建的类,几乎都不会被卸载
  3. 该类的 java.lang.Class 对象没有在任何地方被引用

布隆过滤器的原理是什么?以及主要解决什么问题?

主要解决缓存穿透问题(大量请求访问不存在的数据,大量请求打崩数据库)

核心是一个位数组和hash函数

具体来说,插入一个key时,通过k个hash函数计算出k个不同hash值,然后位数组在k个hash值处置1,每次请求前先根据key和这个key对应的hash值是否置1,就可以判断这个值是否存在

Redis 集群模式下,一致性 Hash 是怎么做的?

利用CRC16循环冗余码对key计算一个16位的整数,然后用16384(槽位数)取模,最后结果就是slot计算得到的hash槽

优点:槽位数固定,增删节点的时候无需改变其他key的位置

缓存三剑客

缓存穿透:非法请求攻击数据库。布隆过滤器,缓存空对象(非法请求第一次访问数据库时,向缓存中添加一条空数据),拒绝非法请求

缓存雪崩:大量key同时过期。设置不同的过期时间,设计架构(熔断控制,限流控制,多级缓存)

缓存击穿:key过期时被大量访问。互斥锁,逻辑过期(不设置过期时间,value中添加一个逻辑过期时间,如果过期了就异步更新一次数据),热数据不过期