阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Redis集群详解

261次阅读
没有评论

共计 4713 个字符,预计需要花费 12 分钟才能阅读完成。

Redis 作为缓存使用,单进程单实例存在的问题:

  • 单点故障
  • 容量有限
  • 压力过大

1|1Redis 主从复制解决单点故障:

 

AKF 拆分原则:

Redis 集群详解

x 轴:全量、镜像。复制多个镜像,解决单点故障

y 轴:按业务功能拆分为多个实例,同时在 x 轴方向同时创建多份镜像。

z 轴:优先级、逻辑再拆分。比如说某个模块数据过多,可以拆分为多个 Redis 客户端,全量数据分为多份,每个 Redis 中存一部分数据。

此时虽然解决了单实例存在的三个问题,那么又会带来数据一致性问题。

解决数据一致性问题:

  • 同步阻塞方式:

    Redis 集群详解

    假如说一个客户端做了一个写操作,到达主 Redis,那么 client 将阻塞,直到主 Redis 通知两个备 Redis 都成功写入才返回结果。这时候为强一致性,带来的问题是,假如说备用 Redis 这时候挂掉,没有写入成功,那么主 Redis 等待超时之后,就返回给客户端失败,相当于服务不可用,破坏了可用性。

  • 异步方式:

    • 弱一致性:

      Redis 集群详解

      容忍数据丢失一部分,当 client 发送一个写请求,Redis 立刻返回 OK,这时候通知备 Redis 去写,如果两个都写失败了,那么就会丢失数据。

    • 最终一致性:

      Redis 集群详解

      这种方式虽然数据最终会一致,但是在这期间如果有客户端去读数据,可能会造成脏读。

小知识:主备与主从的区别

主备:备机一般不参与业务,当主挂了之后,备机可以代替主去提供服务。

主从:客户端可以访问主,也可以访问从。

Redis 一般使用主从复制的模式,但是此时主自己又是一个单点。

对主做 HA 高可用:

对主做高可用并不是说不让主出现问题,而是对外表现为没有出现问题。人工可以去把其中一个从机设置为主,让另一个从去追随它。但是人往往是不可靠的,所以需要技术或程序来实现,主要是一个程序就会有单点故障的问题,所以程序也必须是一个集群。

假如说有三个监控程序监控一个主 Redis 的存活状态,那么也就是说 Redis 的存活状态由三个监控程序说了算。

  • 强一致性,都给出 OK:假如说都给出 OK,才表示 Redis 存活,那么必然会破坏可用性,比如说其中一个监控阻塞了,而实际 Redis 还存活,这相当于监控不可用,所以不可取。

  • 一部分给出 OK,另一部分不算数:那么一部分是几个呢?假如拿三个监控举例,那么就只能是 1 或者 2。

    推导过程:

    • 1 个:统计不准确,不够势力范围,因为每个都可以做主。可能会导致数据不一致,会有网络分区的问题,对外表现为同一服务拿到的数据不同,也就是脑裂。

      并不是说发生脑裂不好,有个概念叫分区容忍性。比如说 SpringCloud 中的 Eureka 注册中心,假如说本来有十个服务注册到不同的 Eureka 中,负载的时候需要打到不同的机器上,每个负载发现的服务机器数不一致,但并不影响,对客户端来说,只要有服务可用即可。

    • 2 个:这个时候会有两台结成势力范围,两台之间互相通信,这时候给出的结果就是 Redis 要么存活,要么挂了,不会有中间状态。

    2 在 3 个节点成功解决脑裂问题,3 在 4 / 5 个节点成功解决脑裂问题,可以得出结论,当有 n 个节点的时候需要 n /2+1,也就是过半,一般使用奇数台。

    为什么是奇数台?

    1. 3 台、4 台能承受的风险都是只允许 1 台出现问题,4 台的成本更高。

    2. 4 台的时候比 3 台更容易出现问题,即 1 台出现问题的概率更大。

主从复制配置:

  • replica-serve-stale-data yes

    表示一个 Redis 在启动之后,并且将追随一个主 Redis,在主给生成 RDB 文件到从 Redis 去 load RDB 文件之前,是否提供查询服务。no 的话,直到全部同步完之前不提供服务。

  • replica-read-only yes

    备机是否开启只读模式。

  • repl-diskless-sync no

    主 Redis 发送 RDB 有两种方式,第一种方式是通过落到磁盘,从 Redis 再去 load,第二种方式是直接通过网络发送RDB 传给从 Redis。这就取决于磁盘 IO 和网络 IO 哪个更快一些。配置 no 的话默认是走磁盘方式。
    Redis 集群详解

  • repl-backlog-size 1mb

    主从复制,增量复制。在 Redis 中,除了写入 RDB 文件外,还维护一个小的队列。当从 Redis loadRDB 之后,突然挂掉了,然后服务又好了,这时候又需要去同步数据,但是此时的 RDB 文件已经过时,可以把 RDB 文件重新覆盖一遍,但是如果此时文件很大的话,又需要浪费时间。此时可以把一个偏移量给到主 Redis,然后根据偏移量去获取增量数据,但是这时候取决于队列大小,默认为 1MB,如果写的速度非常慢,在这期间没有超过设置的大小,那么是可以的,但是如果写的数据非常多,超过了设置的大小,那么又会走全量复制,所以要根据实际写入的数据设置合适的队列大小。
    Redis 集群详解

  • min-replicas-to-write 3 min-replicas-max-lag 10

    可以设置最少写几个写成功,当关心数据一致性的时候,可以设置。默认是注释掉的,如果设置的话其实是在向强一致性靠拢,所以需根据实际应用场景配置。

HA 高可用(x 轴):

sentinel哨兵代替人工去自动修复故障,可以是单机也可以是集群,只监控 master 节点,因为 master 节点上有 slave 节点信息,通过发布订阅发现其他哨兵。

1|2Redis 解决容量问题:

 

解决方案 client 端:

  1. 当数据可以拆分的时候,可以按业务逻辑拆分,并分配到各个 Redis 实例。

    Redis 集群详解

  2. 当数据不可拆分的时候,有三种解决方案(sharding分片):

    这三种模式都只能作为缓存用,不能做数据库用。

    • 利用算法:hash+ 取模(modula),模的大小为 Redis 实例数。当 key 经过 hash 之后,存放在某一台 Redis 实例中。

      弊端:取模的数必须固定,当再增加 Redis 实例时,可能会取不到原来的值,需要重新取模,全局洗牌,影响分布式下的扩展性。

      Redis 集群详解

    • random随机:这种有一个应用场景,一般用于 list 类型,即消息队列。当并发流量大时,可以用 Redis 作为缓冲,但是一台实例有扛不住,可以多搞几台,每一台上有相同的 key,当clientlpush一个 key 时,随机写到一台 Redis 实例中,另一个 clientrpop,这个 key 其实相当于 topic,而每个 Redis 相当于partition,就是kafka 的模型,只不过 kafka 是基于磁盘的,数据可以重新消费,Redis 是基于内存的,速度快。

      Redis 集群详解

    • 一致性哈希(ketama)

      规划一个环形哈希环,环上有很多点,比如说 0~2^32,然后有一个映射算法(如 hash、md5 等很多),有两个 Redis 节点,分别为 node01node02,把这两个节点信息通过一个 hash 算法映射到这个环上某一个点,这两个点是物理的,其他的点都是虚拟的。当一个数据(data) 进来时,也经过这个 hash 算法映射在环上某个点,假如说这些点都在一个排好序的集合里(比如说 TreeMap),然后遍历这个 map 去找大于这个点的最近的物理点在哪,找到这个点代表的物理机然后存放进去,即存到了node02 中。假如说现在想加一个 node03,经过hash 后恰巧分配到了两个物理节点之间。

      优点:增加节点可以分担其他节点的压力,不会造成像取模一样全局洗牌。

      缺点:

      • 问题:新增节点导致一小部分数据不能命中,可能会造成缓存击穿。

      • 方案:每次取的时候,找离我最近的两个物理节点。

      那么在取不到的数据存在 node02 节点上会造成空间浪费,可以利用 Redis 自带的回收策略,例如LRULFU

      扩展 :在哈希环上增加虚拟节点,一个物理设备可以通过hash 算法映射为多个虚拟节点,使数据存储更均匀。

      Redis 集群详解

server端方案:

上述算法都是发生在客户端的,那么当客户端连接 Redis 的时候,socket连接过多,对 server 端的影响是连接成本很高。

Redis 集群详解

此时可以用代理的方式解决,让所有的客户端去连接中间代理,此时 server 端的 socket 连接压力不大,只需要关心代理层性能即可。

Redis 集群详解

所谓无状态,就是本身并不需要数据库,不需要存储数据,数据是存在后端的,只有达到无状态的代理,像 Nginx 这种,才更容易一变多。

如果客户端很多,前面压力过大,一台代理撑不住的话,代理可以做一个集群,在代理之前还可以加一层 LVS,不需要对代理层做高可用,因为如果LVS 挂掉的话,后面服务都不可用了,所以 LVS 会做一个主备,主备之间靠 keepalived 来管理,除了可以监控 LVS 之外,还可以监控代理层的健康状态,如果其中一台代理挂了,那么只会走另一台。

Redis 集群详解

预分区:

不管是在 client 还是 proxy 的算法,新增一台 Redis 的时候总会有问题,要么重新取模全局洗牌,要么丢失一部分数据,所以干脆一开始取模值大一点,比如说取模为 10,模数值的范围 0 9。此时中间还需要一层 `mapping` 做映射,假如说一开始有两台 Redis1 和 Redis12,Redis1 上是 0 4 槽位,Redis2 上是 5~9 槽位,这样新增一个节点的时候,只需要从之前的 Redis 上让出几个槽位即可。那么在数据迁移的过程中,允不允许修改?这时候可以先把时点数据 RDB 传过去,再把增量的日志传过去。

Redis 集群实现:

cluster模式 :只需要一个client,并且是无主模型,client 连哪一个都行,在每一个 Redis 都有 hash 算法,还需要有其他 Redis 上的映射关系,假如说 clientget一个 k1,而k1 根据 hash 取模算出来在 4 号槽位,而此时 client 连接 Redis2,那么会返回给客户端并跳转到 key 对应所在的 Redis 节点,找到之后直接返回给 client 即可。(查询路由

Redis 集群详解

数据分治会导致聚合操作难以实现,比如说求两个集合的交集,两个集合在不同的 Redis 节点上。事务也难以支持,Redis 并没有去实现,但可以人为定义进行 hash 的算法,比如说用相同的前缀(键哈希标签),这样数据就会存储到同一 Redis 节点上。

比如这两个键 {user1000}.following 和 {user1000}.followers 会被哈希到同一个哈希槽里,因为只有 user1000 这个子串会被用来计算哈希值。

2|0Redis 常见问题

 

2|1缓存击穿

 

Redis 的 key 会有过期时间,包括自带的 LRULFU 导致的淘汰 key,当在过期的时候,正好有大量并发请求来查询这个key,这个时候请求会直接打到数据库上,称为缓存击穿。强调的是高并发对某个过期key 查询。

解决方案

Redis 是单进程单实例的,用 setnx() 加锁,第一个去获取 key 发现没有,然后加一把锁,加锁成功的话,就去访问数据库,后面的加锁失败,就 sleep 等待,一般根据实际业务场景选择等待时间。

问题 1 :只要加锁就可能会有死锁的问题,假如说第一个人挂了怎么办?

  • 可以设置锁的过期时间

问题 2 :如果没挂,但是访问数据库阻塞了,导致锁超时了怎么办?

  • 使用多线程,一个线程取数据库,一个线程监控是否取回来,更新锁的时间。但是这样的话会增加业务代码的复杂度。

Redis 集群详解

2|2缓存穿透

 

从业务系统接收到的查询请求的是系统中根本不存在的数据,称为缓存穿透。

解决方案

布隆过滤器:三种使用方式

  • client包含:压力到不了 Redis,客户端代码复杂度高。
  • client只写算法,bitmap在 Redis。
  • Redis 集成布隆,客户端轻盈。

布隆过滤器的一个缺点是不能删除,如果有必要的话可以用布谷鸟过滤器,或者把 key 的值设为null

Redis 集群详解

2|3缓存雪崩

 

大量的 key 同时失效,间接造成大量的访问到达数据库,为缓存雪崩。

解决方案

两方面,一是时点性无关的话,把过期时间随机,防止大量 key 同时过期。

如果是业务上 0 点,或者 1 点失效的话,可以强依赖击穿方案,也可以在业务层加判断,做零点延迟,这样压力不会到 Redis。

Redis 集群详解

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计4713字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中