Redis高可用集群
分布式架构设计的核心思想
- 高性能:读写分离、分片集群
- 高可用:数据持久化、多副本、故障自动转移
- 易扩展:分片集群、横向扩展
- 分布式共识:哨兵,领导者选举
- 负载均衡:数据分片、数据路由
单机版Redis
业务 -> Redis -> MySQL
这个架构非常简单,你的业务应用可以把 Redis 当做缓存来使用,从 MySQL 中查询数据,然后写入到 Redis 中,之后业务应用再从 Redis 中读取这些数据,由于 Redis 的数据都存储在内存中,所以这个速度飞快。
但是,突然有一天,你的 Redis 因为某些原因宕机了,这时你的所有业务流量,都会打到后端 MySQL 上,这会导致你的 MySQL 压力剧增,严重的话甚至会压垮 MySQL。
数据持久化,解决重启丢失问题
- RDB:
- 只持久化某一时刻的数据快照 到磁盘上(创建一个子进程来执行)
- 采用二进制+数据压缩的方式写磁盘,这样文件体积小,数据恢复速度也快
- AOF:
- 每一次写操作都持久到磁盘(主线程写内存,根据策略可以配置由主线程还是子线程进行数据持久化)
- 记录的是每一次的写命令,数据最全,文件体积大、数据恢复慢
Redis数据持久化方案选择:
- 如果业务对数据丢失不敏感,使用RDB
- 如果业务对数据完整性有要求,使用AOF
选择AOF方案,在业务积累下数据恢复变的很慢,该如何处理
AOF的特点是将每一次的写命令都记录起来,对于同一个Key
的多次操作,我们其实只需要最后一次写操作的记录即可。即:**[AOF rewrite]**
我们对AOF文件定时rewrite,避免这个文件持续膨胀,减少恢复耗时
利用RDB、AOF的特点,实现Redis的 混合持久化
注意:Redis 4.0以上版本才支持混合持久化
步骤:
- 在AOF进行rewrite时候,
- Redis先以RDB格式在AOF文件中写入一个数据快照,
- 再把在这期间产生的每一个命令,追加到AOF文件中。
- 因为RDB是二进制压缩写入,所以文件更小
主从多副本
一个实例宕机,只能用恢复数据来解决,那我们是否可以部署多个 Redis 实例,然后让这些实例数据保持实时同步,这样当一个实例宕机时,我们在剩下的实例中选择一个继续提供服务就好了。即:主从结构
业务
-读/写->Redis Master
-实时同步->Redis slave
这里把实时读写的Redis叫做master
, 实时同步数据的Redis叫做slave
多副本的优势:
- 缩短不可用的时间:master 发送宕机时,我们可以手动把slave提升master继续提供服务
- 提升读性能:通过slave分担一部分读请求,提升整体服务性能
它的问题在于:当 master 宕机时,我们需要「手动」把 slave 提升为 master,这个过程也是需要花费时间的。
主从哨兵,故障自动切换
引入一个观察者,让他去实时监测master
的健康状态,这个观察者就是哨兵
- 哨兵每隔一段时间,询问master是否正常
- master正常回复,代表正常,回复超时代表异常
- 哨兵接收到异常,发起主从切换
隐患:master 状态正常,但是回复哨兵的时候网络异常,导致哨兵误判
解决方法:部署多个哨兵,一起检测master的状态,采用选举投票的方式来最终确定master状态是否正常。
- 多个哨兵间隔询问master是否正常
- master回复正常,或超时异常
- 一旦有一个哨兵判定master异常(无论是否网络问题),就询问其他哨兵,如果多个哨兵都收到master异常,就判定故障执,通过
共识算法
由领导者执行主从切换
共识算法:规定节点的数量必须是奇数个,这样可以保证系统中即使有节点发生了故障,剩余超过「半数」的节点状态正常,依旧可以提供正确的结果,也就是说,这个算法还兼容了存在故障节点的情况。
共识算法在分布式系统领域有很多,例如 Paxos、Raft,哨兵选举领导者这个场景,使用的是 Raft 共识算法,因为它足够简单,且易于实现。
分片集群
什么是「分片集群」?
简单来讲,一个实例扛不住写压力,那我们是否可以部署多个实例,然后把这些实例按照一定规则组织起来,把它们当成一个整体,对外提供服务,这样不就可以解决集中写一个实例的瓶颈问题吗?
多实例如何组织:
- 每个节点各自存一分部数据,所有节点数据加起来才是全量数据
- 指定一个路由规则,不同的Key规则数据路由到不同节点上
分片集群根据路由规则所在的不同位置,分为两大类:
- 客户端分片:Key的路由规则由业务客户端来做
- 缺点:需要把路由规则写到业务代码中
- 解决方法:把路由规则封装成一个模块,使用时集成这个模块。这就是
Redis Cluster
SDK采用的方法 Redis Cluster内置哨兵逻辑
- 服务端分片
- 在客户端和服务端中间增加
Proxy
层,数据的路由规则放在代理层。无需关心服务端有多少redis节点,只需要和Proxy交互 - Proxy会把你的请求根据路由规则,转发到对应的Redis节点上,而且当集群扩容节点时,对客户端来说是无感的
业界开源的 Redis 分片集群方案,例如 Twemproxy、Codis 就是采用的这种方案。