Redis

1、redis过期键删除?

 定期删除 + 惰性删除

  • 定期删除 :默认每隔100ms随机抽取一些设置了过期时间的key进行删除
  • 惰性删除 :查询key的时候,懒惰的检查一下

2、内存淘汰机制?

  • noeviction : 当内存不足以容纳新写入数据时,新写入数据会报错
  • allkeys-lru :移除最近最少使用的key(最常用)
  • allkeys-random : 随机
  • volatile-lru : 在设置了过期时间的key中,移除最近最少使用的key
  • volatile-random : 过期key中,随机删除

3、手写LRU算法

public class LRUCache<K,V> extends LinkedHashMap<K,V> {
    
  private int cacheSize;
  
  public LRUCache(int cacheSize) {
      super(16,0.75f,true);
      this.cacheSize = cacheSize;
  }

  /**
   * 判断元素个数是否超过缓存容量
   */
  @Override
  protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
      return size() > cacheSize;
  }
}

4、如何保证Redis的高并发和高可用?Redis的主从复制原理?哨兵原理?

  • 高并发:主从架构,一主多从,一般来说很多项目已经足够了,单主用来写入数据,单机几万QPS,多从用来查询数据,可以水平扩展
  • 高可用:Sentinel哨兵 + Redis主从,哨兵本身是分布式的,至少需要3个实例
  • 异步复制导致数据丢失、脑裂:min-slave-to-writer、min-slave-max-lag
  • 哨兵的master选举算法:
    • 跟master断开的时间长度
    • 优先级
    • 复制offset
    • run id 
    • quorum数量的哨兵认为sdown就会转换为odown,然后得到majority数量哨兵的授权,转换为master

5、RDB 和 AOF

  •  RDB持久化就是把当前进程数据生成快照保存到磁盘的过程。
  •  触发的机制 :
    • 手动触发: bgsave 和 save 命令
      • save : 阻塞直至RDB操作完成
      • bgsave : fork子进程,RDB持久化交给子进程完成
    • 自动触发: 
      • save相关配置 ,比如说save m n 那么就是如果数据集在m秒内改动了n次,就触发
      • shutdown,如果没有开启AOF配置,那么默认执行RDB
      • 从节点进行全量复制的时候
  • AOF:
    • 以append-only模式将每次的写命令存在独立的文件中,系统重启通过重放命令达到数据恢复的效果
    • 触发机制:
      • bgrewriteaof
      • 根据auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage参数
    • 流程:
      • 所有写命令追加到aof_buf缓冲区中
      • AOF缓冲区根据对应的策略像磁盘做同步操作(always :每条写命令都写磁盘,everysec :fsync操作每秒执行一次 ,no :同步硬盘操作由系统完成,通常最长30秒)
      • 随着AOF文件越来越大,需要定期向AOF文件进行重写,达到压缩的目的
        • 内过期数据不再写入文件
        • 将无效命令直接由内存数据生成,如del key,set a 1、set a 2
      • Redis重启重放AOF文件,进行数据恢复

6、缓存穿透和缓存雪崩?

   缓存雪崩

  • 场景:缓存宕机,大量请求打到数据库直接打死
  • 解决:
    • 事前:Redis高可用 
    • 事中:本地ehcache缓存 + hystrix限流和降级,防止数据库被打死
    • 事后:redis持久化机制恢复内存数据

  缓存穿透

  • 场景:瞬时大量的不存在的key请求,数据库又被打死了
  • 解决:每次只要查不到,就写一个空值到缓存中去

7、缓存与数据库双写一致性?

  读的时候先读缓存,缓存没有就读数据库,然后取出数据放入缓存,同时返回响应。写的时候先删除缓存,后更新数据库。

  高并发的情况下还是会出现双写不一致问题,可以将相同key的读写放在一个队列中(可以通过hash值对队列数量取模),达到顺序执行的效果。

 8、Redis并发竞争问题?

  分布式锁保证同一时间只能有一个系统能操作key,写的时候判断本次的时间戳是否晚于db库中的时间戳。

9、为什么redis那么快

  • 内存操作
  • 非阻塞的IO多路复用
  • 单线程避免了上下文切换的性能消耗

10、redis的文件事件处理器

 

 

  

一次完整的客户端与服务器连接事件示例:

  • 一个redis客户端向服务器发起连接,产生一个AE_READABLE事件,触发连接应答处理器执行。处理器响应客户端连接请求,创建客户端套接字并将客户端套接字的AE_READABLE事件与命令请求处理器关联,使得客户端可以向服务器发送命令请求
  • 客户端向服务器发送一个命令请求,那么客户端套接字会产生一个AE_READABLE事件,引发命令请求处理器执行
  • 服务器将客户端套接字的AE_WRITABLE事件与命令回复处理器进行关联,当客户端尝试读取命令回复的时候,客户端将产生AE_READABLE事件,触发命令回复处理器执行,当命令回复处理器将命令回复全部写入套接字后,服务器会解除客户端套接字AE_WRITEABLE事件与命令回复处理器之间的联系。

11、Redis的应用场景

  • 缓存
  • 共享session
  • 消息队列
  • 分布式锁

12、Redis支持的数据类型 (看看自己的redis整理)

  • String
  • list
  • hash
  • set
  • zset
  • HyperLogLog :
    • pfadd(添加)、pfcount(统计)、pfmerge(合并多个key的计数)、pf是发明者的英文首字母
    • 准备率在0.81
    • 在计数比较小时,它的存储空间采用稀疏矩阵存储,空间占用很小,仅仅在计数慢慢变大,稀疏矩阵占用空间渐渐超过了阈值时才会一次性转变成稠密矩阵,才会占用 12k 的空间
    • HyperLogLog 实现中用到的是 16384 个桶,也就是 2^14,每个桶的 maxbits 需要 6 个 bits 来存储,最大可以表示 maxbits=63,于是总共占用内存就是2^14 * 6 / 8 = 12k字节。
  • Bloom Filter :当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在
    • bf.add : 添加元素
    • bf.exists : 查询元素是否存在
    • bf.madd : 批量添加
    • bf.mexists : 批量查询元素是否存在
    • 向布隆过滤器询问 key 是否存在时,跟 add 一样,也会把 hash 的几个位置都算出来,看看位数组中这几个位置是否都为 1,只要有一个位为 0,那么说明布隆过滤器中这个 key 不存在。如果都是 1,这并不能说明这个 key 就一定存在,只是极有可能存在,因为这些位被置为 1 可能是因为其它的 key 存在所致
  • geo :
    • geoadd 指令携带集合名称以及多个经纬度名称三元组,注意这里可以加入多个三元组
    • geodist 指令可以用来计算两个元素之间的距离,携带集合名称、2 个名称和距离单位
    • geopos 指令可以获取集合中任意元素的经纬度坐标,可以一次获取多个
    • geohash 可以获取元素的经纬度编码字符串
    • georadiusbymember 指令是最为关键的指令,它可以用来查询指定元素附近的其它元素
    • georadius 根据用户的定位来计算「附近的车」,「附近的餐馆」等.它的参数和 georadiusbymember 基本一致,除了将目标元素改成经纬度坐标值

13、skipList跳表的数据结构

  • 跳跃表是在一种有序数据结构,它通过在每个节点维护多个指向其他节点的指针,从而达到快速访问节点的目的
  •  有待补充

  

 

posted @ 2020-08-06 14:11  TPL  阅读(135)  评论(0编辑  收藏  举报