Redis 提供了三种集群策略:
对于这三种模式,如果 Redis 要存的数据量不⼤,可以选择哨兵模式,如果 Redis 要存的数据量⼤,并且需要持续的扩容,那么选择Cluster 模式。
通过持久化功能,Redis 保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据,因为持久化会把内存中数据保存到硬盘上,重启会从硬盘上加载数据。 但是由于数据是存储在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失。
为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务。
为此, Redis 提供了复制(replication)功能,能使得从 Redis 服务器(下文称 slave)能精确得复制主 Redis 服务器(下文称 master)的内容。每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。

这个系统的运行依靠三个主要的机制:
Redis 复制的重要特性:
每一个 Redis master 都有一个 replication ID :这是一个较大的伪随机字符串,标记了一个给定的数据集。每个 master 也持有一个偏移量,master 将自己产生的复制流发送给 slave 时,发送多少个字节的数据,自身的偏移量就会增加多少,目的是当有新的操作修改自己的数据集时,它可以以此更新 slave 的状态。复制偏移量即使在没有一个 slave 连接到 master 时,也会自增,所以基本上每一对给定的 Replication ID, offset 都会标识一个 master 数据集的确切版本。
当 slave 连接到 master 时,它们使用 PSYNC 命令来发送它们记录的旧的 master replication ID 和它们至今为止处理的偏移量。通过这种方式, master 能够仅发送 slave 所需的增量部分。但是如果 master 的缓冲区中没有足够的命令积压缓冲记录,或者如果 slave 引用了不知道的历史记录(replication ID),则会转而进行一个全量重同步:在这种情况下, slave 会得到一个完整的数据集副本,从头开始。
在 Redis2.8 之前只能使用 sync 命令来主从同步数据就是全量复制,sync 命令会在不管 slave 是第一次启动还是断线重连都会全量的去复制数据,在 Redis2.8 之后使用 psync 命令来完成主从数据同步,psync 弥补对 sync 只能全量同步数据的问题,psync 的同步过程分为全量复制跟增量复制。
断开重连后,2.8之后的版本会将断线期间的命令传给重数据库,增量复制。
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。Redis 的策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
Redis2.8 之前的同步数据是 SYNC 命令的全量复制,初始化和断线重连都是使用的全量复制。

为了解决 Redis2.8 之前的版本中断线情况下 SYNC 进行全量同步的低效问题,在 Redis 2.8 之后使用 PSYNC 命令代替 SYNC 命令执行同步操作,PSYNC 具备了数据全量重同步 和 部分重同步模式
PSYNC 同步有几个重要的概念:runid、offset(复制偏移量)以及复制积压缓冲区。
PSYNC 中发送的这个 ID 是指之前连接的 master 的 ID,如果没保存这个 ID,PSYNC 的命令会使用 PSYNC ? -1 这种形式发送给 master,表示需要全量复制。
如上图所示
PSYNC执行过程和SYNC的区别在于:salve 连接时,判断是否需要全量同步,全量同步的逻辑过程和SYNC一样。
PSYNC执行步骤如下:
SLAVEOF 命令,即 salve 向 master 发起连接请求时,slave 根据自己是否保存 master runid 来判断是否是第一次连接。 PSYNC ? -1 命令来进行全量同步;如果是重连接,会向 master 发送PSYNC runid offset 命令(runid 是 master 的身份ID,offset 是从节点同步命令的全局迁移量)。PSYNC 命令后,首先判断 runid 是否和本机的 id 一致,如果一致则会再次判断 offset 偏移量和本机的偏移量相差有没有超过复制积压缓冲区大小,如果没有那么就给 slave 发送 CONTINUE,此时 slave只需要等待 master 传回失去连接期间丢失的命令。FULLRESYNC runid offset,slave 将 runid 保存起来,并进行全量同步。在写操作命令传播时,master 会将每一个写命令传递给 slave,同时也会将写命令存放到积压队列,并记录当前积压队列中存放命令的全局偏移量 offset。当 salve 重连接时,master 会根据从节点传的 offset 在环形积压队列中找到断开这段时间执行的命令,并同步给 salve 节点,达到增量同步结果。
# 默认情况下积压队列的大小为1MB,可以通过配置文件设置队列大小;积压队列越大,允许主从数据库断线的时间就越长
repl-backlog-size 1mb
# 当没有salve连接时,默认一小时可以释放环形队列,可以通过配置设置释放时间(单位秒)
repl-backlog-ttl 3600
第一种主从同步/复制的模式,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。为了解决这一问题,我们可以使用哨兵模式。
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:
哨兵模式是一种特殊的模式,首先 Redis 提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待 Redis 服务器响应,从而监控运行的多个 Redis 实例

具体流程如下:
然而一个哨兵进程对 master 进行监控,也可能会出现问题,比如:如果 master 状态正常,但这个哨兵在询问 master 时,它们之间的网络发生了问题,那这个哨兵可能会误判。为此,我们可以部署多个哨兵,让它们分布在不同的机器上,它们一起监测 master 的状态。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

具体流程如下:
一个 Sentinel 可以与其他多个 Sentinel 进行连接, 各个 Sentinel 之间可以互相检查对方的可用性, 并进行信息交换。
你无须为运行的每个 Sentinel 分别设置其他 Sentinel 的地址, 因为 Sentinel 可以通过 发布与订阅功 能来自动发现正在监视相同主服务器的其他 Sentinel , 这一功能是通过向频道 sentinel:hello 发送信息来实现的。
与此类似, 你也不必手动列出主服务器属下的所有从服务器, 因为 Sentinel 可以通过询问主服务器来获得所有从服务器的信息。
PING 命令。PING 命令的时间超过 down-after-milliseconds 选项所指定的值,则这个实例会被 sentinel 标记为主观下线。主观下线,则正在监视这个 master 的所有 sentinel 要以每秒一次的频率确认master 的确进入了 主观下线 状态。主观下线,当有足够数量的 sentinel(大于等于配置文件指定的值)在指定的时间范围内确认 master 的确进入了 主观下线 状态,则 master 会被标记为 客观下线。INFO 命令。当一个 master 被 sentinel 标记为 客观下线 时,sentinel 向下线的 master 的所有 slave 发送 INFO 命令的频率会从10秒一次改为每秒一次。客观下线状态就会被移除。 若 master 重新向 sentinel 的 PING 命令返回有效回复,master 的 主观下线 状态就会被移除。前面说过, Redis 的 Sentinel 中关于下线(down)有两个不同的概念:
如果一个服务器没有在 down-after-milliseconds 选项所指定的时间内, 对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线。
服务器对 PING 命令的有效回复可以是以下三种回复的其中一种:
如果服务器返回除以上三种回复之外的其他回复, 又或者在指定时间内没有回复 PING 命令, 那么 Sentinel 认为服务器返回的回复无效(non-valid)。
注意, 一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 Sentinel 标记为主观下线。举个例子:如果 down-after-milliseconds 选项的值为 30000 毫秒(30 秒), 那么只要服务器能在每 29 秒之内返回至少一次有效回复, 这个服务器就仍然会被认为是处于正常状态的。
客观下线条件只适用于主服务器: 对于任何其他类型的 Redis 实例, Sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器或者其他 Sentinel 永远不会达到客观下线条件。
只要一个 Sentinel 发现某个主服务器进入了客观下线状态, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对失效的主服务器执行自动故障迁移操作
当一个 master 被判断客观下线以后,多个监视该服务的 sentinel 协商,选举一个领头 sentinel,对并由该领导者节点对其进行故障转移操作。
监视该主节点的所有哨兵都有可能被选为领导者,选举使用的算法是 Raft 算法;Raft 算法的基本思路是先到先得:即在一轮选举中,哨兵 A 向 B 发送成为领导者的申请,如果 B 没有同意过其他哨兵,则会同意 A 成为领导者。is-master-down-by-addr 这个命令有两个作用,一是确认下线判定,二是进行领导者选举
Raft 是一种为了管理复制日志的一致性算法,主要用来解决分布式系统一致性问题。Raft 提供了和 Paxos 算法相同的功能和性能,但是它的算法结构和 Paxos 不同。Raft 算法更加容易理解并且更容易构建实际的系统。
Raft 将一致性算法分解成了3模块:leader选举、日志复制、安全性。
Raft 算法分为两个阶段,首先是选举过程,然后在选举出来的领导人带领进行正常操作,比如日志复制等,这里简单介绍一下 leader 选举。
Raft 将系统中的角色分为以下三种:
Term:Raft 协议将时间切分为一个个的 Term(任期),可以认为是一种逻辑时间。
在 Raft 中,任何时候一个服务器都可以扮演下面的角色之一:Leader、Follower、Candidate;当server启动时,初始状态都是 follower。**每一个 server 都有一个定时器,超时时间为 election timeout(一般为150-300ms),如果某 server 没有超时的情况下收到来自领导者或者候选者的任何消息,定时器重启,如果超时,它就开始一次选举。**如下图:

Raft 采用心跳机制触发 Leader 选举,系统启动后:
全部节点初始化为 Follower,term 为0。
节点如果收到了 RequestVote 或者 AppendEntries,就会保持自己的 Follower 身份
节点如果一段时间内没收到 AppendEntries 消息,在该节点的超时时间内还没发现 Leader,Follower 就会转换成 Candidate,自己开始竞选 Leader。
一旦转化为 Candidate,该节点立即开始下面几件事情:
如果在计时器超时前,节点收到多数节点的同意投票,就转换成 Leader。同时向所有其他节点发送 AppendEntries,告知自己成为了 Leader。
每个节点在一个 term 内只能投一票,采取先到先得的策略,Candidate 前面说到已经投给了自己, Follower 会投给第一个收到 RequestVote 的节点。
Raft 协议的定时器采取随机超时时间,这是选举 Leader 的关键。
在同一个 term 内,先转为 Candidate 的节点会先发起投票,从而获得多数票。
某 Sentinel 认定 master 客观下线后,该 Sentinel 会先看看自己有没有投过票,如果自己已经投过票给其他 Sentinel 了,在一定时间(election timeout)内自己就不会成为 Leader。
如果该 Sentinel 还没投过票,那么它就成为 Candidate。
Sentinel 需要完成几件事情:
is-master-down-by-addr 命令请求投票。命令会带上自己的 epoch。当其它哨兵收到此命令时,可以同意或者拒绝它成为领导者(通过判断 epoch);
Candidate 会不断的统计自己的票数,直到发现认同自己成为 Leader 的票数超过一半而且超过它配置的 quorum,这时它就成为了 Leader。
其他 Sentinel 等待 Leader 从 slave 选出 master 后,检测到新的 master 正常工作后,就会去掉客观下线的标识。
一次故障转移操作由以下步骤组成:
客观下线 状态。SLAVEOF NO ONE 命令,让它转变为主服务器。每当一个 Redis 实例被重新配置(reconfigured) —— 无论是被设置成主服务器、从服务器、又或者被设置成其他主服务器的从服务器 —— Sentinel 都会向被重新配置的实例发送一个 CONFIG REWRITE 命令, 从而确保这些配置会持久化在硬盘里。
Sentinel 使用以下规则来选择新的主服务器:
slave-priority 最高的节点;slave-priority 一样,选出复制偏移量(replication offset)最大的那个从服务器作为新的主服务器,因为复制偏移量越大则数据复制的越完整;Sentinel 节选举成为 Leader 的最低票数为 quorum 和 Sentinel节点数/2+1 的最大值,如果 Sentinel 集群只有2个 Sentinel 节点,则
Sentinel节点数/2 + 1
= 2/2 + 1
= 2
即 Leader 最低票数至少为2,当该 Sentinel 集群中由一个 Sentinel 节点故障后,仅剩的一个 Sentinel 节点是永远无法成为 Leader。
也可以由此公式可以推导出,Sentinel 集群允许1个 Sentinel 节点故障则需要3个节点的集群;允许2个节点故障则需要5个节点集群。
优点:
缺点:
为什么需要 Redis 集群?
在讲 Redis 集群架构之前,我们先简单讲下 Redis 单实例的架构,从最开始的一主N从,到读写分离,再到 Sentinel 哨兵机制,单实例的 Redis 缓存足以应对大多数的使用场景,也能实现主从故障迁移。但是,在某些场景下,单实例存 Redis 缓存会存在的几个问题:
Redis 主从架构+ Sentinel 仍存在问题:
Redis Cluster 是一种服务器 Sharding 技术,3.0版本开始正式提供。
Redis 的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存,所以在 redis3.0 上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,也就是说每台 Redis 节点上存储不同的内容,其结构图如下:

Redis Cluster特性:
(分片存储)Redis3.0 加入了 Redis 的集群模式,实现了数据的分布式存储,对数据进行分片,将不同的数据存储在不同的 master 节点上面,从而解决了海量数据的存储问题。
(指令转换)Redis 集群采用去中心化的思想,没有中心节点的说法,对于客户端来说,整个集群可以看成一个整体,可以连接任意一个节点进行操作,就像操作单一 Redis 实例一样,不需要任何代理中间件,当客户端操作的 key 没有分配到该 node 上时,Redis 会返回转向指令,指向正确的 Redis 节点。
(主从和哨兵)Redis 也内置了高可用机制,支持N个 master 节点,每个 master 节点都可以挂载多个 slave 节点,当 master 节点挂掉时,集群会提升它的某个 slave 节点作为新的 master 节点。
Redis 集群通过分布式存储的方式解决了单节点的海量数据存储的问题,对于分布式存储,需要考虑的重点就是如何将数据进行拆分到不同的 Redis 服务器上。常见的分区算法有hash算法、一致性hash算法。
哈希算法的思想非常简单,与我们所熟知的 HashMap 的 hash 函数类似,通过一个哈希函数得到某一个数字,然后根据数字取模找到相应的服务器。
比如有 N 个 redis 实例,那么如何将 key 映射到 redis 上呢?
通常是采用 hash 算法计算 key 的 hash 值,然后通过取模,均匀的映射到N个 redis 服务器上 hash(key)%N。
但是如果增加一个服务器,那么映射公式就变成了 hash(key)%(N+1);如果有一个服务器宕机了,映射公式变成了 hash(key)%(N-1)。这种情况下,几乎所有的缓存都失效了,会导致数据库访问的压力陡增,甚至导致数据库宕机。
hash算法优点就是比较简单,属于静态的分片规则。但是一旦节点数量变化,新增或者减少,由于取模的 N 发生变化, 数据需要重新分布和迁移。
一致性哈希算法可以说是哈希算法的升级版,解决了哈希算法扩展性差的问题,一致性哈希算法跟哈希算法不一样,一致性哈希算法会将服务器和数据都通过哈希函数映射到一个首尾相连的虚拟的圆环(哈希环)上,整个空间按顺时针方向组织。因为是环形空间,0 和 2^32-1 是重叠的(总共2^32个)。
具体步骤如下:
首先根据服务器(节点)的名称或 IP 计算出哈希值,并将其配置到哈希环上。
然后采用同样的方法求出存储数据的键的哈希值,得到哈希环中相应的位置。
然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个大于等于该哈希值的 Node 上。如果超过 2^32 仍然找不到服务器,就会保存到第一台服务器上。
新增或删减节点,数据仍然会进行漂移,但是影响范围就很小了,只会影响到相邻的节点。

优点:在加入和删除节点时只影响相邻的两个节点,缺点:加减节点会造成部分数据无法命中。所以一般用于缓存,而且用于节点量大的情况下,扩容一般增加一倍节点保障数据负载均衡。
此外,针对于 hash 节点分散不均匀或者倾倒状态,一致性哈希算法引入了
虚拟节点的概念。所谓虚拟节点,就是基于原来的物理节点映射出N个子节点,最后把所有的子节点映射到环形空间上。虚拟节点越多,分布越均匀。

Redis 集群既没有用哈希取模,也没有用一致性哈希,而是用 hash 槽来实现的。Redis 集群创建了 16384 个槽(slot),每个节点负责一定区间的 slot。
具体流程:
根据 Redis 主节点的数量来分配 slot,每个节点负责一定区间的 slot
集群会对使用 CRC16 算法对 key 进行计算并对 16384 取模 (slot = CRC16(key)%16384)
得到的结果就是 Key-value 对所放入的 slot,通过这个 slot 去找对应的 Redis 节点
然后直接到这个对应的节点上进行存取操作
举个例子,比如当前集群有3个节点,那么:
这种结构很容易添加或者删除节点:
由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态。
在 Redis 的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383。还有一个就是 cluster,可以理解为是一个集群管理的插件。当我们的存取的 Key 到达的时候,Redis 会根据 CRC16 的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
注意:key 与 slot 的关系是永远不会变的,会变的只有 slot 和 Redis 节点的关系
(1)请求重定向
客户端可能会挑选任意一个 redis 实例去发送命令,每个 redis 实例接收到命令,都会计算 key 对应的 hash slot,如果在本地就在本地处理,否则返回 moved 给客户端,让客户端进行重定向
cluster keyslot mykey,可以查看一个 key 对应的 hash slot 是什么
用 redis-cli 的时候,可以加入 -c 参数,支持自动的请求重定向,redis-cli 接收到 moved 之后,会自动重定向到对应的节点执行命令
(2)计算 hash slot
计算 hash slot 的算法,就是根据 key 计算 CRC16 值,然后对 16384 取模,拿到对应的 hash slot
用 hash tag 可以手动指定 key 对应的 slot,同一个 hash tag 下的 key,都会在一个 hash slot 中,比如:
set mykey1:{100}
set mykey2:{100}
(3)hash slot 查找
节点间通过 gossip 协议进行数据交换,就知道每个 hash slot 在哪个节点上
(1)什么是 smart jedis
基于重定向的客户端,很消耗网络 IO,因为大部分情况下,可能都会出现一次请求重定向,才能找到正确的节点
所以大部分的客户端,比如 java redis 客户端,就是 jedis,都是 smart 的
本地维护一份 hashslot -> node 的映射表,缓存,大部分情况下,直接走本地缓存就可以找到 hashslot -> node,不需要通过节点进行 moved 重定向
(2)JedisCluster 的工作原理
在 JedisCluster 初始化的时候,就会随机选择一个 node,初始化 hashslot -> node 映射表,同时为每个节点创建一个 JedisPool 连接池
每次基于 JedisCluster 执行操作,首先 JedisCluster 都会在本地计算 key 的 hashslot,然后在本地映射表找到对应的节点
如果那个 node 正好还是持有那个 hashslot,那么就 ok;如果说进行了 reshard 这样的操作,可能 hashslot 已经不在那个 node上了,就会返回 moved
如果 JedisCluter API 发现对应的节点返回 moved,那么利用该节点的元数据,更新本地的 hashslot -> node 映射表缓存
重复上面几个步骤,直到找到对应的节点,如果重试超过5次,那么就报错 JedisClusterMaxRedirectionException
jedis 老版本,可能会出现在集群某个节点故障还没完成自动切换恢复时,频繁更新 hash slot,频繁 ping 节点检查活跃,导致大量网络 IO 开销
jedis 最新版本,对于这些过度的 hash slot 更新和 ping,都进行了优化,避免了类似问题
(3)hashslot 迁移和 ask 重定向
如果 hash slot 正在迁移,那么会返回 ask 重定向给 jedis
jedis 接收到 ask 重定向之后,会重新定位到目标节点去执行,但是因为 ask 发生在 hash slot 迁移过程中,所以 JedisCluster API 收到 ask 是不会更新 hashslot 本地缓存
已经可以确定说,hashslot 已经迁移完了,moved 是会更新本地 hashslot->node 映射表缓存的
1.基础通信
(1)redis cluster 节点间采取 gossip 协议进行通信
跟集中式不同,不是将集群元数据(节点信息,故障,等等)集中存储在某个节点上,而是互相之间不断通信,保持整个集群所有节点的数据是完整的
集中式:好处在于,元数据的更新和读取,时效性非常好,一旦元数据出现了变更,立即就更新到集中式的存储中,其他节点读取的时候立即就可以感知到;不好在于,所有的元数据的跟新压力全部集中在一个地方,可能会导致元数据的存储有压力
gossip:好处在于,元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,降低了压力; 缺点,元数据更新有延时,可能导致集群的一些操作会有一些滞后
(2)10000 端口
每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如 7001,那么用于节点间通信的就是 17001 端口
每隔节点每隔一段时间都会往另外几个节点发送 ping 消息,同时其他几点接收到 ping 之后返回 pong
(3)交换的信息
故障信息,节点的增加和移除,hash slot 信息,等等
2. gossip协议
meet:某个节点发送 meet 给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信
ping:每个节点都会频繁给其他节点发送 ping,其中包含自己的状态还有自己维护的集群元数据,互相通过 ping 交换元数据 每个节点每秒都会频繁发送 ping 给其他的集群,ping 频繁的互相之间交换数据,互相进行元数据的更新
pong: 返回 ping 和 meet,包含自己的状态和其他信息,也可以用于信息广播和更新
fail:某个节点判断另一个节点 fail 之后,就发送 fail 给其他节点,通知其他节点,指定的节点宕机了
为了保证高可用,redis-cluster 集群引入了主从复制模型,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点 。
当其它主节点 ping 一个主节点 A 时,如果半数以上的主节点与 A 通信超时,那么认为主节点 A 宕机了。如果主节点 A 和它的从节点 A1 都宕机了,那么该集群就无法再提供服务了。
默认情况下,redis 集群的读和写都是到 master 上去执行的,不支持 slave 节点读和写,跟 Redis 主从复制下读写分离不一样,因为 redis 集群的核心的理念,主要是使用 slave 做数据的热备,以及 master 故障时的主备切换,实现高可用的。
Redis 的读写分离,是为了横向任意扩展 slave 节点去支撑更大的读吞吐量。而 redis 集群架构下,本身 master 就是可以任意扩展的,如果想要支撑更大的读或写的吞吐量,都可以直接对 master 进行横向扩展。
Redis 集群至少需要3个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以2个节点无法构成集群。
要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,所以 Redis 集群至少需要6台服务器。
登录redis后,在里面可以进行下面命令操作
# 集群
cluster info # 打印集群的信息
cluster nodes # 列出集群当前已知的所有节点( node),以及这些节点的相关信息。
# 节点
cluster meet <ip> <port> # 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
cluster forget <node_id> # 从集群中移除 node_id 指定的节点。
cluster replicate <master_node_id> # 将当前从节点设置为 node_id 指定的master节点的slave节点。只能针对slave节点操作。
cluster saveconfig # 将节点的配置文件保存到硬盘里面。
# 槽(slot)
cluster addslots <slot> [slot ...] # 将一个或多个槽( slot)指派( assign)给当前节点。
cluster delslots <slot> [slot ...] # 移除一个或多个槽对当前节点的指派。
cluster flushslots # 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
cluster setslot <slot> node <node_id> # 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给
cluster setslot <slot> migrating <node_id> # 将本节点的槽 slot 迁移到 node_id 指定的节点中。
cluster setslot <slot> importing <node_id> # 从 node_id 指定的节点中导入槽 slot 到本节点。
cluster setslot <slot> stable # 取消对槽 slot 的导入( import)或者迁移( migrate)。
# 键
cluster keyslot <key> # 计算键 key 应该被放置在哪个槽上。
cluster countkeysinslot <slot> # 返回槽 slot 目前包含的键值对数量。
cluster getkeysinslot <slot> <count> # 返回 count 个 slot 槽中的键 。
创建集群
redis-cli --cluster create 192.168.100.100:6379 192.168.100.101:6379 192.168.100.102:6379 192.168.100.103:6379 192.168.100.104:6379 192.168.100.105:6379 --cluster-replicas 1
添加一个新主节点
# 需要添加的新节点为 "192.168.100.106:6379",先以单机版配置和启动好,然后执行命令(“192.168.100.100:6379”为集群中任一可用的节点)
redis-cli --cluster add-node 192.168.100.106:6379 192.168.100.100:6379
# 重新分配哈希槽
redis-cli --cluster reshard 192.168.100.106:6379
添加一个从节点
# "192.168.100.106:6380" 为新添加的从节点,"192.168.100.100:6379" 可为集群中已有的任意节点,这种方法随机为6380指定一个master
redis-cli --cluster add-node 192.168.100.106:6380 192.168.100.100:6379 --cluster-slave
# 如果想明确指定master,假设目标master的ID为 "23b412673af0506df6382353e3a65960d5b7e66d",则:
redis-cli --cluster add-node 192.168.100.106:6380 192.168.100.100:6379 --cluster-slave --cluster-master-id 23b412673af0506df6382353e3a65960d5b7e66d
删除节点
# 从集群中删除一个节点命令格式:`redis-cli --cluster del-node <cluster-node> <node-id>`
# `cluster-node`为集群中任意一个非待删除节点,`node-id`为待删除节点的ID。
# 如果待删除的是master节点,则在删除之前需要将该master负责的slots先全部迁到其它master。
redis-cli --cluster del-node 192.168.100.100:6379 963fb30a8ca0a424b50215f733205ff182104953
查看 key 属于哪个 slot:
redis> cluster keyslot yan
让相关的数据落到同一个节点上
# 在key里面加入 {hash tag} 即可。Redis在计算槽编号的时候只会获取 {} 之间的字符串进行槽编号计算,这样由于上面两个不同的键,{} 里面的字符串是相同的,因此他们可以被计算出相同的槽。
set mykey1:{100}
set mykey2:{100}
优点:
无中心架构。
数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
可扩展性,可线性扩展到 1000个节点(官方推荐不超过 1000 个)节点可动态添加或删除。
高可用性,部分节点不可用时,集群仍可用。通过增加 Slave做 standby 数据副本,能够实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave 到 Master 的角色提升。
降低运维成本,提高系统的扩展性和可用性。
缺点: