分布式架构设计的核心思想

  • 高性能:读写分离、分片集群
  • 高可用:数据持久化、多副本、故障自动转移
  • 易扩展:分片集群、横向扩展
  • 分布式共识:哨兵,领导者选举
  • 负载均衡:数据分片、数据路由

Redis集群

单机版Redis

业务 -> Redis -> MySQL

这个架构非常简单,你的业务应用可以把 Redis 当做缓存来使用,从 MySQL 中查询数据,然后写入到 Redis 中,之后业务应用再从 Redis 中读取这些数据,由于 Redis 的数据都存储在内存中,所以这个速度飞快。

但是,突然有一天,你的 Redis 因为某些原因宕机了,这时你的所有业务流量,都会打到后端 MySQL 上,这会导致你的 MySQL 压力剧增,严重的话甚至会压垮 MySQL。

数据持久化,解决重启丢失问题

  1. RDB:
  • 只持久化某一时刻的数据快照 到磁盘上(创建一个子进程来执行)
  • 采用二进制+数据压缩的方式写磁盘,这样文件体积小,数据恢复速度也快
  1. AOF:
  • 每一次写操作都持久到磁盘(主线程写内存,根据策略可以配置由主线程还是子线程进行数据持久化)
  • 记录的是每一次的写命令,数据最全,文件体积大、数据恢复慢

Redis数据持久化方案选择:

  • 如果业务对数据丢失不敏感,使用RDB
  • 如果业务对数据完整性有要求,使用AOF

选择AOF方案,在业务积累下数据恢复变的很慢,该如何处理
AOF的特点是将每一次的写命令都记录起来,对于同一个Key的多次操作,我们其实只需要最后一次写操作的记录即可。即:**[AOF rewrite]**

我们对AOF文件定时rewrite,避免这个文件持续膨胀,减少恢复耗时

利用RDB、AOF的特点,实现Redis的 混合持久化 注意:Redis 4.0以上版本才支持混合持久化

步骤:

  1. 在AOF进行rewrite时候,
  2. Redis先以RDB格式在AOF文件中写入一个数据快照,
  3. 再把在这期间产生的每一个命令,追加到AOF文件中。
  4. 因为RDB是二进制压缩写入,所以文件更小

主从多副本

一个实例宕机,只能用恢复数据来解决,那我们是否可以部署多个 Redis 实例,然后让这些实例数据保持实时同步,这样当一个实例宕机时,我们在剩下的实例中选择一个继续提供服务就好了。即:主从结构

业务 -读/写-> Redis Master -实时同步-> Redis slave
这里把实时读写的Redis叫做master, 实时同步数据的Redis叫做slave

多副本的优势:

  1. 缩短不可用的时间:master 发送宕机时,我们可以手动把slave提升master继续提供服务
  2. 提升读性能:通过slave分担一部分读请求,提升整体服务性能

它的问题在于:当 master 宕机时,我们需要「手动」把 slave 提升为 master,这个过程也是需要花费时间的。

主从哨兵,故障自动切换

引入一个观察者,让他去实时监测master的健康状态,这个观察者就是哨兵

  • 哨兵每隔一段时间,询问master是否正常
  • master正常回复,代表正常,回复超时代表异常
  • 哨兵接收到异常,发起主从切换

隐患:master 状态正常,但是回复哨兵的时候网络异常,导致哨兵误判
解决方法:部署多个哨兵,一起检测master的状态,采用选举投票的方式来最终确定master状态是否正常。

  • 多个哨兵间隔询问master是否正常
  • master回复正常,或超时异常
  • 一旦有一个哨兵判定master异常(无论是否网络问题),就询问其他哨兵,如果多个哨兵都收到master异常,就判定故障执,通过共识算法由领导者执行主从切换

共识算法:规定节点的数量必须是奇数个,这样可以保证系统中即使有节点发生了故障,剩余超过「半数」的节点状态正常,依旧可以提供正确的结果,也就是说,这个算法还兼容了存在故障节点的情况。
共识算法在分布式系统领域有很多,例如 Paxos、Raft,哨兵选举领导者这个场景,使用的是 Raft 共识算法,因为它足够简单,且易于实现。

分片集群

什么是「分片集群」?

简单来讲,一个实例扛不住写压力,那我们是否可以部署多个实例,然后把这些实例按照一定规则组织起来,把它们当成一个整体,对外提供服务,这样不就可以解决集中写一个实例的瓶颈问题吗?

多实例如何组织:

  • 每个节点各自存一分部数据,所有节点数据加起来才是全量数据
  • 指定一个路由规则,不同的Key规则数据路由到不同节点上

分片集群根据路由规则所在的不同位置,分为两大类:

  1. 客户端分片:Key的路由规则由业务客户端来做
  • 缺点:需要把路由规则写到业务代码中
  • 解决方法:把路由规则封装成一个模块,使用时集成这个模块。这就是Redis ClusterSDK采用的方法 Redis Cluster内置哨兵逻辑
  1. 服务端分片
  • 在客户端和服务端中间增加Proxy层,数据的路由规则放在代理层。无需关心服务端有多少redis节点,只需要和Proxy交互
  • Proxy会把你的请求根据路由规则,转发到对应的Redis节点上,而且当集群扩容节点时,对客户端来说是无感的

业界开源的 Redis 分片集群方案,例如 Twemproxy、Codis 就是采用的这种方案。

原文地址