实现 Redis 的高可用,主要有 哨兵 和 集群 两种方式。
Redis Sentinel(哨兵)是一个 分布式架构,它包含 若干 哨兵节点 和 数据节点,每个哨兵节点 会对 数据节点 和 其余的哨兵节点 进行监控,当发现节点不可达(节点发生宕机)时,会对节点做 下线标识。
如果 被标识的 是 主节点,它就会与 其它的哨兵节点 进行协商,当 多数哨兵节点 都认为 主节点 不可达时,它们便会选举出一个 哨兵节点 来完成 自动故障转移 的工作,同时还会将这个变化实时地通知给 应用方(整个过程是自动完成,不需要人工介入)。
注:一组哨兵 可以监控 一个(或多个)主节点。
补充:哨兵节点的特征
Redis 集群 采用 虚拟槽分区 来实现 数据分片,它把 所有的键 根据 哈希函数映射 到 0 - 16383 整数槽内(计算公式为 slot = CRC16(key)&16383
),每一个节点 负责维护一部分 槽和槽所映射的键值数据。
虚拟槽分区的特点:
主从同步,是指将一台 Redis 服务器的数据,复制到其它的 Redis 服务器上,前者称为主节点(Master),后者称为从节点(Slave)。数据的复制是单向的,只能由主节点复制到从节点(主节点以写为主、从节点以读为主)。
注:默认情况下,每台 Redis 服务器 都是主节点,一个主节点可以有 0 个或者多个从节点,但每个从节点只能有一个主节点。
Redis 使用 psync 命令 完成主从同步,同步过程分为 全量复制 和 部分复制,全量复制 一般用于 初次复制的场景,部分复制 则用于 处理因网络中断 等原因 造成数据丢失的场景。
psync 命令 所需要的 参数:
当写入数据将导致超出 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 的基础上,为每个数据增加了一个计数器,来统计该数据的访问次数,当 内存超出限制 时,首先会将 访问次数最低 的数据淘汰出去,如果两个数据的访问次数相同,则将 访问时间更早 的数据淘汰出去。
惰性删除
客户端访问一个 key 的时候,Redis 会先检查它的过期时间,如果发现过期就立刻删除这个 key 。
定期删除
Redis 会将设置了过期时间的 key 放到一个独立的字典中,并对该字典进行每秒 10 次的过期扫描,过期扫描不会遍历字典中所有的 key,而是采用了一个种简单的贪心策略:
问题描述:
客户端查询根本不存在的数据,使得请求知道存储层,导致其负载过大,甚至宕机。出现这个情况的原因,可能是业务层误将缓存和库中的数据删除了,也可能是有人恶意攻击,专门访问库中不存在的数据。
解决方案:
缓存空对象
存储层未命中后,仍然将空值存入缓存层,客户端再次访问数据时,缓存层会直接返回空值。
布隆过滤器
将数据存入布隆过滤器,访问缓存之前以过滤器拦截,若请求的数据不存在,则直接返回空值。
扩展:布隆过滤器
问题描述:
一份热点数据,它的访问量非常大,在其缓存失效的瞬间,大量请求知道存储层,导致服务奔溃。
解决方案:
永不过期
热点数据不设置过期时间,或者 为每个数据设置逻辑过期时间,当发现该数据逻辑过期时,使用单独的线程重建缓存。
加互斥锁
对数据的访问加互斥锁,当一个线程访问数据时,其它线程只能等待,这个线程访问过后,缓存中的数据将被重建,届时其它线程就可以直接从缓存中取值。
问题描述:
在某一时刻,缓存层无法继续提供服务,导致所有的请求知道存储层,造成数据库宕机,可能是缓存中有大量数据同时过期,也可能是 Redis 节点发生故障,导致大量请求无法得到处理。
解决方案:
避免数据同时过期
设置过期时间时,附加一个随机数,避免大量的 key 同时过期。
启动降级和熔断措施
在发生雪崩时,若应用访问的不是核心数据,则直接返回预定义信息 / 空值 / 错误信息,或者 在发生雪崩时,对于访问缓存接口的请求,客户端并不会把请求发给 Redis,而是直接返回。
构建高可用的 Redis 服务
采用哨兵或集群模式,部署多个 Redis 实例,个别节点宕机,依然可以保持服务的整体可用。
4 种同步策略:
扩展:延时双删