Redis 集群是一种分布式的 Redis 系统,通过数据分片和负载均衡来提高 Redis 的性能和可用性。下面介绍几种常见的 Redis 集群方案:
- 主从模式:Redis 主从复制是一种基于主从架构的数据复制方式,其中一个 Redis 服务器作为主节点,实现读写分离
- Redis Sentinel:Redis 官方提供的高可用方案,可以监控 Redis 节点的状态,并在节点故障时进行自动切换。Redis Sentinel 可以实现主从复制、故障转移和自动故障检测等功能,同时也支持多个 Sentinel 节点之间的信息同步和状态转移。
- Redis Cluster:Redis 官方提供的 Redis 集群方案,支持横向扩展,自动进行数据分片和负载均衡,同时也提供故障转移和容错功能。Redis Cluster 通过 Gossip 协议实现节点间的信息传递和状态同步,同时也支持节点间的复制和持久化。
- 其他方案:携程的Codis、推特的Twemproxy以及第三方集群方案,例如 Redisson、Redission 和 JedisCluster 等支持多种 Redis 客户端协议,并提供了 web 界面管理工具。
主从模式
redis单节点虽然有通过RDB和AOF持久化机制能将数据持久化到硬盘上,但数据是存储在一台服务器上的,如果服务器出现硬盘故障等问题,会导致数据不可用,而且读写无法分离,读写都在同一台服务器上,请求量大时会出现I/O瓶颈,为了避免 单点故障 和 读写不分离,Redis 提供了 复制(replication)
功能实现master数据库中的数据更新后,会自动将更新的数据同步到其他slave数据库上

主从结构特点:一个master可以有多个salve节点;salve节点可以有slave节点,从节点是级联结构
优缺点:
-
优点: 主从结构具有读写分离,提高效率、数据备份,提供多个副本等优点。
-
不足: 不具备自动容错和恢复功能,主节点故障,集群则无法进行工作,可用性比较低,从节点升主节点需要人工手动干预。
当主数据库崩溃时,需要手动切换从数据库成为主数据库:
- 在从数据库中使用
SLAVE NO ONE
命令将从数据库提升成主数据继续服务。 - 启动之前崩溃的主数据库,然后使用
SLAVEOF
命令将其设置成新的主数据库的从数据库,即可同步数据。
主从复制原理
为了实现主从复制,那么就会存在以下几个问题
- 如何确定主从关系的
- 如何进行全量同步与增量同步的
- 同步过程中新的写命令是如何处理的
全量复制
全量复制分为三个阶段

第一阶段:从库发送 psync
命令,表示要进行数据同步。psync
命令包含了主库的 runID 和复制进度 offset 两个参数。
-
runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为
?
-
offset,此时设为 -1,表示第一次复制。
主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。
第二阶段:主库同步数据给从库
-
主库执行 bgsave 命令,生成 RDB 文件,接着将文件发给从库。
-
从库收到 RDB 文件后,先清空当前数据库,然后加载 RDB 文件。
注意:
- 清空当前数据库是为了避免有旧数据
- 主库同步数据给从库过程中,主库不会阻塞,过程中新产生的写命令会存储在主库 replication buffer内存中
第三阶段:主库会把第二阶段执行过程中新收到的写命令,再发送给从库
如果在同步 replication buffer 过程中,又有新的写命令怎么办?
同步过程中网络断了,如果不进行全量同步,那么怎么知道数据同步到哪里了?
增量同步
每次都进行全量同步的陈本很高,所以就添加的增量同步的逻辑

这里有两个缓存, replication buffe
r 在上一节也是在全量同步过程中用于记录 同步过程中的新写命令
-
repl_backlog_buffer
:为了能找到主从差异数据而设计的环形缓冲区,从而避免全量复制带来的性能开销。如果从库断开时间太久,repl_backlog_buffer
环形缓冲区被主库的写命令覆盖了,那么从库连上主库后只能乖乖地进行一次全量复制,所以repl_backlog_buffer配置尽量大一些,可以降低主从断开后全量复制的概率。而在repl_backlog_buffer
中找主从差异的数据后,如何发给从库呢?这就用到了replication buffer
。 -
replication buffer
:Redis和客户端通信也好,和从库通信也好,每个client 都会分配一个replication buffer
进行数据交互,所有数据交互都是通过这个buffer进行的。所以主从在增量同步时,从库作为一个client,也会分配一个buffer,专门用来传播用户的写命令到从库,保证主从数据一致。
**主从模式主服务器必须开启持久化!**因为从库可能会因为主库崩溃没有数据而在同步过程中将从库的数据全部删掉
哨兵模式
主从模式异常情况下,需要人工干预,哨兵模式巧妙解决。哨兵模式核心还是主从复制,只不过在相对于主从模式在主节点宕机导致不可写的情况下,多了一个竞选机制:从所有的从节点竞选出新的主节点。竞选机制的实现,是依赖于在系统中启动一个sentinel
进程。

哨兵本身也有单点故障的问题,所以在一个一主多从的Redis系统中,可以使用多个哨兵进行监控,哨兵不仅会监控主数据库和从数据库,哨兵之间也会相互监控。每一个哨兵都是一个独立的进程,作为进程,它会独立运行

哨兵的作用:
-
监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。
-
自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
-
配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
-
通知(Notification):哨兵可以将故障转移的结果发送给客户端
哨兵的原理
哨兵在启动进程时,会读取配置文件的内容,通过如下的配置找出需要监控的主数据库:
1 | sentinel monitor master-name ip port quorum |
之所以只需要连接主节点,是因为通过主节点的info命令,获取从节点信息,从而和从节点也建立连接,同时也能通过主节点的info信息知道新增从节点的信息。
一个哨兵节点可以监控多个主节点,但是并不提倡这么做,因为当哨兵节点崩溃时,同时有多个集群切换会发生故障。哨兵启动后,会与主数据库建立两条连接。
- 订阅主数据库
_sentinel_:hello
频道以获取同样监控该数据库的哨兵节点信息 - 定期向主数据库发送info命令,获取主数据库本身的信息。
跟主数据库建立连接后会定时执行以下三个操作:
- 每隔10s向master和 slave发送info命令。作用是获取当前数据库信息,比如发现新增从节点时,会建立连接,并加入到监控列表中,当主从数据库的角色发生变化进行信息更新。
- 每隔2s向主数据里和从数据库的
_sentinel_:hello
频道发送自己的信息。作用是将自己的监控数据和哨兵分享。每个哨兵会订阅数据库的_sentinel:hello
频道,当其他哨兵收到消息后,会判断该哨兵是不是新的哨兵,如果是则将其加入哨兵列表,并建立连接。 - 每隔1s向所有主从节点和所有哨兵节点发送ping命令,作用是监控节点是否存活。
主客观下线
- 主观下线:任何一个哨兵都是可以监控探测,并作出Redis节点下线的判断;
- 客观下线:有哨兵集群共同决定Redis节点是否下线;
哨兵节点发送ping命令时,当超过一定时间(down-after-millisecond
)后,如果节点未回复,则哨兵认为主观下线。主观下线表示当前哨兵认为该节点已经下面,如果该节点为主数据库,哨兵会进一步判断是够需要对其进行故障切换,这时候就要发送命令(SENTINEL is-master-down-by-addr
)询问其他哨兵节点是否认为该主节点是主观下线,当达到指定数量(quorum)时,哨兵就会认为是客观下线。
当主节点客观下线时就需要进行主从切换,主从切换的步骤为:
-
选出领头哨兵(Raft),需要同时满足以下两个条件
- 第一,拿到半数以上的赞成票;
- 第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值
-
过滤出不健康的(下线或者不响应哨兵ping响应)
-
领头哨兵所有的slave选出优先级高的从数据库。优先级可以通过
slave-priority
选项设置。 -
如果优先级相同,则从复制的命令偏移量越大(即复制同步数据越多,数据越新),越优先。
-
如果以上条件都一样,则选择run ID较小的从数据库。
选出一个从数据库后,哨兵发送slave no one
命令升级为主数据库,发送slaveof
命令将其他从节点的主数据库设置为新的主数据库。
故障转移
转移前

-
将slave-1脱离原从节点(PS: 5.0 中应该是
replicaof no one
),升级主节点, -
将从节点slave-2指向新的主节点
-
通知客户端主节点已更换
-
将原主节点(oldMaster)变成从节点,指向新的主节点
转移后

哨兵模式优缺点
优点
- 哨兵模式是基于主从模式的,解决可主从模式中master故障不可以自动切换故障的问题。
缺点
- 是一种中心化的集群实现方案:始终只有一个Redis主机来接收和处理写请求,写操作受单机瓶颈影响。
- 集群里所有节点保存的都是全量数据,浪费内存空间,没有真正实现分布式存储。数据量过大时,主从同步严重影响master的性能。
- Redis主机宕机后,哨兵模式正在投票选举的情况之外,因为投票选举结束之前,谁也不知道主机和从机是谁,此时Redis也会开启保护机制,禁止写操作,直到选举出了新的Redis主机。
Redis Cluster
主从模式或哨兵模式每个节点存储的数据都是全量的数据,数据量过大时,就需要对存储的数据进行分片后存储到多个redis实例上。此时就要用到Redis Sharding
技术。
Redis Sharding
客户端分片
是通过一致性hash对Key的访问转发到不同的Redis实例中,查询数据时把返回结果汇集
- 优点:分片逻辑都在客户端不依赖第三方分布式中间件,服务端的Redis实例彼此独立,相互无关联。每个实例都能拓展
- 缺点:增加或减少Redis实例,需要手工调整分片的程序,不同客户端程序都需要公用一套Redis集群
代理分片
代理分片即是通过中间件的形式,将请求转发到代理,由代理对多个Redis统一管理,例如推特的Twemproxy、豌豆荚的Codis
- 优点:客户端无序关心存储、分片逻辑,减少客户端与Redis实例连接数(所以代理也需要可拓展,防止单点故障)
- 缺点:请求转发一次会产生性能消耗
Cluster集群模式
redis在3.0上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,也就是说每台 Redis 节点上存储不同的数据。cluster模式为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/QPS不受限于单机,可受益于分布式集群高扩展性。
Redis Cluster是一种服务器Sharding技术(分片和路由都是在服务端实现),采用多主多从,每一个分区都是由一个Redis主机和多个从机组成,片区和片区之间是相互平行的。Redis Cluster集群采用了P2P的模式,完全去中心化。

官方推荐,集群部署至少要 3 台以上的master节点,3 主 3 从六个节点的模式。Redis Cluster集群具有如下几个特点:
- 集群完全去中心化,采用多主多从;所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
- 客户端与 Redis 节点直连,不需要中间代理层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
- 每一个分区都是由一个Redis主机和多个从机组成,分片和分片之间是相互平行的。
- 每一个master节点负责维护一部分槽,以及槽所映射的键值数据;集群中每个节点都有全量的槽信息,通过槽每个node都知道具体数据存储到哪个node上。
在 Redis Cluster 中,客户端通过连接任意一个节点,该节点将根据哈希槽的方式将请求转发到相应的节点上进行处理。在 Redis Cluster 中,有以下几种请求
- 对于 key 的读写请求:如果请求的 key 所对应的槽在当前节点上,该节点将直接处理该请求;如果请求的 key 所对应的槽在其他节点上,当前节点将将该请求转发到相应的节点上进行处理。
- 对于非 key 的读写请求(例如 incr、decr 等命令):这类请求不涉及具体的 key,因此可以在任意一个节点上进行处理。
在 Redis Cluster 中,数据同步通过 Gossip 协议实现,每个节点都会周期性地向其他节点发送消息,以获取最新的集群信息和数据同步状态。当某个节点出现故障时,其他节点会立即进行检测和处理,将该节点负责的哈希槽自动迁移至其他节点上,以保证数据的高可用性和一致性
redis cluster主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster,数据量不是很大时,使用sentinel就够了。redis cluster的性能和高可用性均优于哨兵模式。
Redis Cluster采用虚拟哈希槽分区而非一致性hash算法,预先分配一些卡槽,所有的键根据哈希函数映射到这些槽内,每一个分区内的master节点负责维护一部分槽以及槽所映射的键值数据。
keys hash tags
Hash tags提供了一种途径,用来将多个(相关的)key分配到相同的hash slot中。这时Redis Cluster中实现multi-key操作的基础。
hash tag规则如下,如果满足如下规则,{
和}
之间的字符将用来计算HASH_SLOT,以保证这样的key保存在同一个slot中。
- key包含一个
{
字符 - 并且 如果在这个
{
的右面有一个}
字符 - 并且 如果在
{
和}
之间存在至少一个字符
例如:
- {user1000}.following和{user1000}.followers这两个key会被hash到相同的hash slot中,因为只有user1000会被用来计算hash slot值。
- foo{}{bar}这个key不会启用hash tag因为第一个{和}之间没有字符。
- foozap{bar}这个key中的**{**bar部分会被用来计算hash slot
- foo{bar}{zap}这个key中的bar会被用来计算计算hash slot,而zap不会
请求重定向
Redis cluster采用去中心化的架构,集群的主节点各自负责一部分槽,客户端如何确定key到底会映射到哪个节点上呢?即请求重定向
在cluster模式下,节点对请求的处理过程如下:
- 检查当前key是否存在当前NODE?
- 通过crc16(key)/16384计算出slot
- 查询负责该slot负责的节点,得到节点指针
- 该指针与自身节点比较
- 若slot不是由自身负责,则返回MOVED重定向
- 若slot由自身负责,且key在slot中,则返回该key对应结果
- 若key不存在此slot中,检查该slot是否正在迁出(MIGRATING)?
- 若key正在迁出,返回ASK错误重定向客户端到迁移的目的服务器上
- 若Slot未迁出,检查Slot是否导入中?
- 若Slot导入中且有ASKING标记,则直接操作
- 否则返回MOVED重定向
这个过程中有两点需要具体理解下: MOVED重定向 和 ASK重定向。
ASK重定向
ASK重定向发生与集群伸缩时候,会要求访问目标

smart客户端
为了降低上述两种重定向复杂性,提供了smart客户端(HedisCluster)来降低复杂度,其实就是客户端内部缓存(key->slot->node)的映射关系

Redis Cluster 不建议使用发布订阅!会将每条publish数据在所有节点之间广播一次
总结
Redis 主从复制是一种基于主从架构的数据复制方式,其中一个 Redis 服务器作为主节点,负责数据写入和数据同步,其他 Redis 服务器作为从节点,负责数据的读取和数据同步。Redis 主从复制提供了数据备份和负载均衡的功能,适用于单节点读写比较频繁的场景。
Redis Cluster 是一种基于分布式架构的集群方案,其中多个 Redis 节点通过哈希槽的方式将数据分散到不同的节点中进行存储和访问。Redis Cluster 提供了数据的自动分片和负载均衡的功能,可以动态地增加或删除节点,并支持故障恢复和数据同步。Redis Cluster 适用于大规模的数据存储和高并发访问的场景。
主从模式和 Redis Cluster 之间的区别主要有以下几个方面:
- 数据复制方式不同:主从模式是一种基于主从架构的数据复制方式,而 Redis Cluster 是一种基于分布式架构的数据存储方案。
- 数据分片方式不同:主从模式中,主节点负责数据的写入和同步,从节点负责数据的读取和同步,而 Redis Cluster 中,数据根据哈希槽的方式分散到多个节点中存储和访问。
- 故障处理方式不同:主从模式中,当主节点出现故障时,需要手动切换到从节点上进行故障处理,而 Redis Cluster 中,当某个节点出现故障时,其他节点可以自动接管该节点负责的哈希槽。
- 扩展性不同:主从模式中,数据量增加时,需要增加更多的从节点进行负载均衡,而 Redis Cluster 中,可以动态地增加或删除节点,以适应不同的数据量和访问量。
总的来说,主从模式适用于单节点读写比较频繁的场景,Redis Cluster 适用于大规模的数据存储和高并发访问的场景。在选择 Redis 集群方案时,需要根据业务场景和实际需求进行评估和选择。