关于 Redis 的这些知识 你知道哪些

发布于:2023-01-09 ⋅ 阅读:(613) ⋅ 点赞:(0)

关于 Redis 的这些知识 你知道哪些


1、Redis 高可用的实现

​  实现 Redis 的高可用,主要有 哨兵 和 集群 两种方式。


1.1、哨兵

​  Redis Sentinel(哨兵)是一个 分布式架构,它包含 若干 哨兵节点 和 数据节点,每个哨兵节点 会对 数据节点 和 其余的哨兵节点 进行监控,当发现节点不可达(节点发生宕机)时,会对节点做 下线标识。

​  如果 被标识的 是 主节点,它就会与 其它的哨兵节点 进行协商,当 多数哨兵节点 都认为 主节点 不可达时,它们便会选举出一个 哨兵节点 来完成 自动故障转移 的工作,同时还会将这个变化实时地通知给 应用方(整个过程是自动完成,不需要人工介入)。

​  注:一组哨兵 可以监控 一个(或多个)主节点。

在这里插入图片描述


补充:哨兵节点的特征

  • 哨兵节点 会 定期 监控数据节点、其它哨兵节点 是否可达;
  • 哨兵节点 会 将 故障转移的结果 通知给应用方;
  • 哨兵节点 可以 将 从节点 晋升为 主节点,并维护后续正确的主从关系;
  • 哨兵模式下,客户端 连接的是 哨兵节点集合,并从中获取主节点信息;
  • 节点的故障判断 是由 多个哨兵节点 共同完成的,可以有效防止误判;
  • 哨兵节点集合 是由 多个哨兵节点 组成,即使 个别哨兵节点 不可用,整个集合依然可以正常工作;
  • 哨兵节点 是 独立的、特殊的 Redis 节点,它们 不存储数据,只支持部分命令。


1.2、集群

​  Redis 集群 采用 虚拟槽分区 来实现 数据分片,它把 所有的键 根据 哈希函数映射 到 0 - 16383 整数槽内(计算公式为 slot = CRC16(key)&16383 ),每一个节点 负责维护一部分 槽和槽所映射的键值数据。

​  虚拟槽分区的特点:

  • 解耦 数据 和 节点 之间的关系,简化了 节点 扩容 和 收缩 的难度;
  • 节点自身 维护 槽的映射关系,不需要 客户端(或代理服务)维护 曹分区的元数据;
  • 支持 节点、槽、键 之间的 映射查询,用于 数据路由、在线伸缩 等场景。

在这里插入图片描述



2、Redis 的主从同步

​  主从同步,是指将一台 Redis 服务器的数据,复制到其它的 Redis 服务器上,前者称为主节点(Master),后者称为从节点(Slave)。数据的复制是单向的,只能由主节点复制到从节点(主节点以写为主、从节点以读为主)。

​  注:默认情况下,每台 Redis 服务器 都是主节点,一个主节点可以有 0 个或者多个从节点,但每个从节点只能有一个主节点。

​  Redis 使用 psync 命令 完成主从同步,同步过程分为 全量复制 和 部分复制,全量复制 一般用于 初次复制的场景,部分复制 则用于 处理因网络中断 等原因 造成数据丢失的场景。

​ psync 命令 所需要的 参数:

  • 复制偏移量
    • 主节点处理写命令后,会把命令长度做累加记录;从节点在接收到写命令后,也会做累加记录;
    • 从节点会每秒上报一次自身的复制偏移量给主节点,而主节点则会保存从节点的复制偏移量。
  • 积压缓存区
    • 保存在主节点上的一个固定长度的队列,默认大小为 1M,当主节点有连接的从节点时被创建出来;
    • 主节点在处理命令时,不但会把命令发送给从节点,还会写入积压缓冲区;
    • 缓存区是先进先出的队列,可以保存最近已复制的数据,用于部分复制和命令丢失的数据补救。
  • 主节点运行 ID
    • 每个 Redis 节点启动后,都会动态分配一个 40 位的十六进制字符串作为运行 ID;
    • 如果使用 IP 和 端口 的方式标识主节点,那么主节点重启变更了数据集(RDB/AOP),从节点再基于复制偏移量复制数据将是不安全的,因此当主节点的运行 ID 变化后,从节点将做全量复制。

在这里插入图片描述
在这里插入图片描述



3、Redis 的淘汰策略

​  当写入数据将导致超出 maxmemory 限制时,Redis 会采用 maxmemory-policy 所指定的策略进行数据淘汰。

​  8 种淘汰策略:

策略 说明
noeviction 直接返回错误
volatile-ttl 从设置了过期时间的键中,选择过期时间最小的键,进行淘汰
volatile-random 从设置了过期时间的键中,随机选择键,进行淘汰
volatile-lru 从设置了过期时间的键中,使用 LRU 算法选择键,进行淘汰
volatile-lfu 从设置了过期时间的键中,使用 LFU 算法选择键,进行淘汰
allkeys-random 从所有的键中,随机选择键,进行淘汰
allkeys-lru 从所有的键中,使用 LRU 算法选择键,进行淘汰
allkeys-lfu 从所有的键中,使用 LFU 算法选择键,进行淘汰

补充:

1、LRU(Least Recently Used,最近最少使用)

  • 标准 LRU

    ​  把所有的数据组成一个链表,表头和表尾分别表示 MRU端 和 LRU 端(即 最常使用端 和 最少使用端),新增的数据(或 刚被访问的数据)会被移动到 MRU 端,当链表的空间被占满时,它会删除 LRU 端的数据。

  • 近似 LRU

    ​  记录每个数据的最近一次访问的时间戳,当 内存超出限制 时,随机采样 N 个 key,淘汰最旧的 key。(可以通过 maxmemory_samples 设置采样个数,默认值为 5)

2、LFU(Least Frequently Used,最少频率使用)

​  在 LRU 的基础上,为每个数据增加了一个计数器,来统计该数据的访问次数,当 内存超出限制 时,首先会将 访问次数最低 的数据淘汰出去,如果两个数据的访问次数相同,则将 访问时间更早 的数据淘汰出去。




4、Redis 的过期策略

  • 惰性删除

    ​  客户端访问一个 key 的时候,Redis 会先检查它的过期时间,如果发现过期就立刻删除这个 key 。

  • 定期删除

    ​  Redis 会将设置了过期时间的 key 放到一个独立的字典中,并对该字典进行每秒 10 次的过期扫描,过期扫描不会遍历字典中所有的 key,而是采用了一个种简单的贪心策略:

    1. 从过期字典中随机选择 20 个 key;
    2. 删除这 20 个 key 中已过期的 key;
    3. 如果过期 key 的比例超过 25%,则重复步骤 1 。


5、缓存穿透、击穿、雪崩

5.1、缓存穿透

问题描述:

​  客户端查询根本不存在的数据,使得请求知道存储层,导致其负载过大,甚至宕机。出现这个情况的原因,可能是业务层误将缓存和库中的数据删除了,也可能是有人恶意攻击,专门访问库中不存在的数据。

解决方案:

  1. 缓存空对象

    ​  存储层未命中后,仍然将空值存入缓存层,客户端再次访问数据时,缓存层会直接返回空值。

  2. 布隆过滤器

    ​  将数据存入布隆过滤器,访问缓存之前以过滤器拦截,若请求的数据不存在,则直接返回空值。


扩展:布隆过滤器

  • 核心组成
    • 一个大型的位数组
    • 若干个不一样的哈希函数,每个哈希函数都能将哈希值算的比较均匀
  • 工作原理
    • 添加 key 时,每个哈希函数都利用这个 key 计算出一个哈希值,再根据哈希值计算一个位置,并将位数组中这个位置的值设置为 1;
    • 询问 key 时,每个哈希函数都利用这个 key 计算出一个哈希值,再根据哈希值计算一个位置,并对比这些哈希函数在位数组中对应位置的数值。
      • 如果这几个位置中,有一个位置的值都是 0,就说明这个布隆过滤器中,不存在这个 key;
      • 如果这几个位置中,所有位置的值都是 1,就说明这个布隆过滤器中,极有可能存在这个 key(存在一定的错误率)。


5.2、缓存击穿

问题描述:

​  一份热点数据,它的访问量非常大,在其缓存失效的瞬间,大量请求知道存储层,导致服务奔溃。

解决方案:

  1. 永不过期

    ​  热点数据不设置过期时间,或者 为每个数据设置逻辑过期时间,当发现该数据逻辑过期时,使用单独的线程重建缓存。

  2. 加互斥锁

    ​ 对数据的访问加互斥锁,当一个线程访问数据时,其它线程只能等待,这个线程访问过后,缓存中的数据将被重建,届时其它线程就可以直接从缓存中取值。


5.3、缓存雪崩

问题描述:

​  在某一时刻,缓存层无法继续提供服务,导致所有的请求知道存储层,造成数据库宕机,可能是缓存中有大量数据同时过期,也可能是 Redis 节点发生故障,导致大量请求无法得到处理。

解决方案:

  1. 避免数据同时过期

    ​  设置过期时间时,附加一个随机数,避免大量的 key 同时过期。

  2. 启动降级和熔断措施

    ​  在发生雪崩时,若应用访问的不是核心数据,则直接返回预定义信息 / 空值 / 错误信息,或者 在发生雪崩时,对于访问缓存接口的请求,客户端并不会把请求发给 Redis,而是直接返回。

  3. 构建高可用的 Redis 服务

    ​  采用哨兵或集群模式,部署多个 Redis 实例,个别节点宕机,依然可以保持服务的整体可用。



6、缓存与数据库的双写一致性

4 种同步策略:

  1. 先更新缓存,再更新数据库;
  2. 先更新数据库,再更新缓存;
  3. 先删除缓存,再更新数据库;
  4. 先更新数据库,再删除缓存(常用)。

扩展:延时双删

  1. 删除缓存;
  2. 更新数据库;
  3. sleep N 毫秒;
  4. 再次删除缓存。


网站公告

今日签到

点亮在社区的每一天
去签到