Redis 集群

Redis 主从复制(replication)

主从复制配置

  • 例如一主多从,203 是主节点,在每个 slave 节点的 redis.conf 配置文件增加一行,slaveof 192.168.8.203 6379

          // 在主从切换的时候,这个配置会被重写成: # Generated by CONFIG REWRITE replicaof 192.168.8.203 6379

  • 或者在启动服务时通过参数指定 master 节点: ./redis-server --slaveof 192.168.8.203 6379

从节点不能写入数据(只读),只能从 master 节点同步数据。get 成功,set 失败

主从复制原理

连接阶段

  1. slave node 启动时(执行 slaveof 命令),会在自己本地保存 master node 的 信息,包括 master node 的 host 和 ip。
  2. slave node 内部有个定时任务 replicationCron(源码 replication.c),每隔 1 秒钟检查是否有新的 master node 要连接和复制,如果发现,就跟 master node 建立 socket 网络连接,如果连接成功,从节点为该 socket 建立一个专门处理复制工作的文件 事件处理器,负责后续的复制工作,如接收 RDB 文件、接收命令传播等。 当从节点变成了主节点的一个客户端之后,会给主节点发送 ping 请求

数据同步阶段

  1. master node 第一次执行全量复制,通过 bgsave 命令在本地生成一份 RDB 快 照,将 RDB 快照文件发给 slave node(如果超时会重连,可以调大 repl-timeout 的值)。 slave node 首先清除自己的旧数据,然后用 RDB 文件加载数据。
  2. 开始生成 RDB 文件时,master 会把所有新的写命令缓存在内存中。在 slave node保存了 RDB 之后,再将新的写命令复制给 slave node。

命令传播阶段

master node 持续将写命令,异步复制给 slave node 延迟是不可避免的,只能通过优化网络。

repl-disable-tcp-nodelay no

当设置为 yes 时,TCP 会对包进行合并从而减少带宽,但是发送的频率会降低,从 节点数据延迟增加,一致性变差;具体发送频率与 Linux 内核的配置有关,默认配置为 40ms。

当设置为 no 时,TCP 会立马将主节点的数据发送给从节点,带宽增加但延迟变小

如果从节点有一段时间断开了与主节点的连接是不是要重新全量复制一遍? 如果可以增量复制,怎么知道上次复制到哪里?

通过 master_repl_offset 记录的偏移量

redis> info replication

可用性保证之 Sentinel

https://redis.io/topics/sentinel

从 Redis2.8 版本起,提供了一个稳定版本的 Sentinel(哨兵),用来解决高可用的问题。Sentinel 通过 info 命令得到被监听 Redis 机器的 master,slave 等信息。

为了保证监控服务器的可用性,我们会对 Sentinel 做集群的部署。Sentinel 既监控 所有的 Redis 服务,Sentinel 之间也相互监控。 注意:Sentinel 本身没有主从之分,只有 Redis 服务节点有主从之分

服务下线

Sentinel 默认以每秒钟 1 次的频率向 Redis 服务节点发送 PING 命令。如果在 down-after-milliseconds 内都没有收到有效回复,Sentinel 会将该服务器标记为下线 (主观下线)。

# sentinel.conf sentinel down-after-milliseconds

这个时候 Sentinel 节点会继续询问其他的 Sentinel 节点,确认这个节点是否下线, 如果多数 Sentinel 节点都认为 master 下线,master 才真正确认被下线(客观下线), 这个时候就需要重新选举 master

故障转移

故障转移流程的第一步就是在 Sentinel 集群选择一个 Leader,由 Leader 完成故障 转移流程。Sentinle 通过 Raft 算法,实现 Sentinel 选举。sentinel.conf 里面的 配置会被修改

Sentinle 的 Raft 算法

Raft 的核心思想:先到先得,少数服从多数

1、master 客观下线触发选举,而不是过了 election timeout 时间开始选举。

2、Leader 并不会把自己成为 Leader 的消息发给其他 Sentinel。其他 Sentinel 等 待 Leader 从 slave 选出 master 后,检测到新的 master 正常工作后,就会去掉客观下线的标识,从而不需要进入故障转移流程

Redis 分布式

如果要实现 Redis 数据的分片,我们有三种方案。

  • 第一种是在客户端实现相关的逻 辑,例如用取模或者一致性哈希对 key 进行分片,查询和修改都先判断 key 的路由。
  • 第二种是把做分片处理的逻辑抽取出来,运行一个独立的代理服务,客户端连接到 这个代理服务,代理服务做请求的转发。
  • 第三种就是基于服务端实现。

客户端 Sharding

Jedis 客户端提供了 Redis Sharding 的方案,并且支持连接池

Sharded 分片的原理?怎么连接到某一个 Redis 服务?

Sharded jedis,提供了一致性hash和md5散列两种hash算法,默认使用一致性hash算法。并且为了使得请求能均匀的落在不同的节点上,Sharded jedis会使用节点的名称(如果节点没有名称使用默认名称)虚拟化出160个虚拟节点。也可以根据不同节点的weight,虚拟化出160*weight个节点。

当客户端访问redis时,首先根据key计算出其落在哪个节点上,然后找到节点的ip和端口进行连接访问

代理 Proxy

典型的代理分区方案有 Twitter 开源的 Twemproxy 和国内的豌豆荚开源的 Codis

Redis Cluster

https://redis.io/topics/cluster-tutorial/

Redis Cluster 是在 Redis 3.0 的版本正式推出的,用来解决分布式的需求,同时也 可以实现高可用。跟 Codis 不一样,它是去中心化的,客户端可以连接到任意一个可用 节点。 数据分片有几个关键的问题需要解决: 1、数据怎么相对均匀地分片 2、客户端怎么访问到相应的节点和数据 3、重新分片的过程,怎么保证正常服务

Cluster 解决分片的问题,数据怎么分布?

  • 哈希后取模

         如果是希望数据分布相对均匀的话,可以考虑哈希后取模。hash(key)%N,根据余数,决定映射到那一个节点。这种方式比较简单,属 于静态的分片规则。但是一旦节点数量变化,新           增或者减少,由于取模的 N 发生变化, 数据需要重新分布。

  • 一致性哈希

把所有的哈希值空间组织成一个虚拟的圆环(哈希环),整个空间按顺时针方向组织。因为是环形空间,0 和 2^32-1 是重叠的。先根据机器的名称或 者 IP 计算哈希值,然后分布到哈希环中。对 key 计算后,得到哈希环中的位置。沿哈希环顺时针找到的第一个 Node,就是数据存储的节点。

Redis 虚拟槽分区

Redis 既没有用哈希取模,也没有用一致性哈希,而是用虚拟槽来实现的。Redis 创建了 16384 个槽(slot),每个节点负责一定区间的 slot。

比如 Node1 负 责 0-5460,Node2 负责 5461-10922,Node3 负责 10923-16383。对象分布到 Redis 节点上时,对 key 用 CRC16 算法计算再%16384,得到一个 slot 的值,数据落到负责这个 slot 的 Redis 节点上。查看 key 属于哪个 slot:

redis> cluster keyslot yan

注意:key 与 slot 的关系是永远不会变的,会变的只有 slot 和 Redis 节点的关系

怎么让相关的数据落到同一个节点上?

在 key 里面加入{hash tag}即可。Redis 在计算槽编号的时候只会获取{}之间的字符 串进行槽编号计算,这样由于上面两个不同的键,{}里面的字符串是相同的,因此他们可 以被计算出相同的槽

客户端连接到哪一台服务器?访问的数据不在当前节点上,怎么办?

  • 客户端重定向

比如在 7291 端口的 Redis 的 redis-cli 客户端操作:

127.0.0.1:7291> set qs 1
(error) MOVED 13724 127.0.0.1:7293

 服务端返回 MOVED,也就是根据 key 计算出来的 slot 不归 7191 端口管理,而是 归 7293 端口管理,服务端返回 MOVED 告诉客户端去 7293 端口操作。 这个时候更换端口,用 redis-cli –p 7293 操作,才会返回 OK。这样客户端需要连接两次。或者用./redis-cli -c -p port 的命令(c 代表 cluster)自动重定向。

新增或下线了 Master 节点,数据怎么迁移(重新分配)?

因为 key 和 slot 的关系是永远不会变的,当新增了节点的时候,需要把原有的 slot 分配给新的节点负责,并且把相关的数据迁移过来。新增的节点没有哈希槽,不能分布数据,在原来的任意一个节点上执行:

redis-cli --cluster reshard 127.0.0.1:7291

输入需要分配的哈希槽的数量(比如 500),和哈希槽的来源节点(可以输入 all 或 者 id)

高可用和主从切换原理

1.slave 发现自己的 master 变为 FAIL

2.将自己记录的集群 currentEpoch 加 1,并广播 FAILOVER_AUTH_REQUEST 信息

3.其他节点收到该信息,只有 master 响应,判断请求者的合法性,并发送 FAILOVER_AUTH_ACK,对每一个 epoch 只发送一次 ack

4.尝试 failover 的 slave 收集 FAILOVER_AUTH_ACK

5.超过半数后变成新 Master

6.广播 Pong 通知其他集群节点。

总结

优势

1. 无中心架构。

2. 数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。

3. 可扩展性,可线性扩展到 1000 个节点(官方推荐不超过 1000 个),节点可动 态添加或删除。

4. 高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做 standby 数据副 本,能够实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制 完成 Slave 到 Master 的角色提升。

5. 降低运维成本,提高系统的扩展性和可用性

不足

1. Client 实现复杂,驱动要求实现 Smart Client,缓存 slots mapping 信息并及时 更新,提高了开发难度,客户端的不成熟影响业务的稳定性。

2. 节点会因为某些原因发生阻塞(阻塞时间大于 clutser-node-timeout),被判断 下线,这种 failover 是没有必要的。

3. 数据通过异步复制,不保证数据的强一致性

4. 多个业务使用同一套集群时,无法根据统计区分冷热数据,资源隔离性较差,容 易出现相互影响的情况。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值