Skip to content

Latest commit

 

History

History
326 lines (170 loc) · 14.6 KB

File metadata and controls

326 lines (170 loc) · 14.6 KB

Redis分布式

1.为什么需要 Redis 集群

1、性能

2、扩展

3、可用性、安全性

2.Redis 主从复制(replication)

2.1 主从复制配置

1、在redis.conf文件中添加一行

slaveof ip port
例如:slaveof 1.1.1.1 6379

2、在启动命令中加

./redis-server --slaveof 1.1.1.1 6379

启动后查看状态

info replication

主节点写入后,slave 会自动从 master 同步数据

2.2 主从复制原理

2.2.1 连接阶段

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 请

2.2.2 数据同步阶段

3、master node 第一次执行全量复制,通过 bgsave 命令在本地生成一份 RDB 快 照,将 RDB 快照文件发给 slave node(如果超时会重连,可以调大 repl-timeout 的值)。 slave node 首先清除自己的旧数据,然后用 RDB 文件

问题:生成 RDB 期间,master 接收到的命令怎么处理?

开始生成 RDB 文件时,master 会把所有新的写命令缓存在内存中。在 slave node保存了 RDB 之后,再将新的写命令复制给 slave node

2.2.3 命令传播阶段

4、master node 持续将写命令,异步复制给 slave node

通过repl-disable-tcp-nodelay no优化网络延迟。

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

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

通过 master_repl_offset 记录的偏移量

2.3 主从复制的不足

1、RDB 文件过大的情况下,同步非常耗时。

2、在一主一从或者一主多从的情况下,如果主服务器挂了,对外提供的服务就不可 用了,单点问题没有得到解决。如果每次都是手动把之前的从服务器切换成主服务器, 这个比较费时费力,还会造成一定时间的服务不可用。

3. 可用性保证之 Sentinel

3.1 Sentinel 原理

image-20220306214620480

为了保证监控服务器的可用性,我们会对 Sentinel 做集群的部署。Sentinel 既监控 所有的 Redis 服务,Sentinel 之间也相互监控。

注意:Sentinel 本身没有主从之分,只有 Redis 服务节点有主从之分。

概念梳理:master,slave(redis group),sentinel,sentinel 集

3.1.1 服务下线

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

# sentinel.conf 
sentinel down-after-milliseconds <master-name> <millisecon

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

3.1.2 故障转移

故障转移流程的第一步就是在 Sentinel 集群选择一个 Leader,由 Leader 完成故障 转移流程。Sentinle 通过 Raft 算法,实现 Sentinel 选举。

Ratf 算法

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

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

故障转移

问题:怎么让一个原来的 slave 节点成为主?

1、选出 Sentinel Leader 之后,由 Sentinel Leader 向某个节点发送 slaveof no one 命令,让它成为独立节点。

2、然后向其他节点发送 slaveof x.x.x.x xxxx(本机服务),让它们成为这个节点的 子节点,故障转移完成。

问题:这么多从节点,选谁成为主节点?

关于从节点选举,一共有四个因素影响选举的结果,分别是断开连接时长、优先级 排序、复制数量、进程 id。

如果与哨兵连接断开的比较久,超过了某个阈值,就直接失去了选举权。如果拥有 选举权,那就看谁的优先级高,这个在配置文件里可以设置(replica-priority 100), 数值越小优先级越高。

如果优先级相同,就看谁从 master 中复制的数据最多(复制偏移量最大),选最多 的那个,如果复制数量也相同,就选择进程 id 最小的那个。

3.2 Sentinel 的功能总结

监控:Sentinel 会不断检查主服务器和从服务器是否正常运行。

通知:如果某一个被监控的实例出现问题,Sentinel 可以通过 API 发出通知

自动故障转移(failover):如果主服务器发生故障,Sentinel 可以启动故障转移过 程。把某台服务器升级为主服务器,并发出通知。

配置管理:客户端连接到 Sentinel,获取当前的 Redis 主服务器的地址

3.3 Sentinel 实战

3.3.1 Sentinel配置

image-20220306220340715

daemonize yes
port 26379
protected-mode no
dir "/usr/local/soft/redis-5.0.5/sentinel-tmp"
sentinel monitor redis-master 192.168.8.203 6379 2
sentinel down-after-milliseconds redis-master 30000
sentinel failover-timeout redis-master 180000
sentinel parallel-syncs redis-master 1

image-20220306220418521

3.3.2 Sentinel验证

3.3.3 Sentinel 连接

3.4 哨兵机制的不足

主从切换的过程中会丢失数据,因为只有一个 master。

只能单点写,没有解决水平扩容的问题。

如果数据量非常大,这个时候我们需要多个 master-slave 的 group,把数据分布到 不同的 group 中。

4. Redis 分布式方案

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

第一种是在客户端实现相关的逻 辑,例如用取模或者一致性哈希对 key 进行分片,查询和修改都先判断 key 的路由。

第二种是把做分片处理的逻辑抽取出来,运行一个独立的代理服务,客户端连接到 这个代理服务,代理服务做请求的转发。

第三种就是基于服务端实现。

4.1 客户端 Sharding

image-20220306222235879

4.1.1 ShardedJedis

4.2 代理 Proxy

image-20220306222316044

4.2.1 Twemprox

image-20220306222328628

Twemproxy 的优点:比较稳定,可用性高。

不足:

1、出现故障不能自动转移,架构复杂,需要借助其他组件(LVS/HAProxy + Keepalived)实现 HA

2、扩缩容需要修改配置,不能实现平滑地扩缩容(需要重新分布数据)。

4.2.2 Codis

Codis 是一个代理中间件,用 Go 语言开发的。 功能:客户端连接 Codis 跟连接 Redis 没有区别。

image-20220306222517015

image-20220306222555138

Codis 的槽位映射关系是保存在 Proxy 中的,如果要解决单点的问题,Codis 也要 做集群部署,多个 Codis 节点怎么同步槽和实例的关系呢?需要运行一个 Zookeeper(或etcd、文件)

在新增节点的时候,可以为节点指定特定的槽位。Codis 也提供了自动均衡策略。

Codis 不支持事务,其他的一些命令也不支持。

获取数据原理(mget):在 Redis 中的各个实例里获取到符合的 key,然后再汇总 到 Codis 中。

Codis 是第三方提供的分布式解决方案,在官方的集群功能稳定之前,Codis 也得到 了大量的应用。

4.3 Redis Cluster

数据分片有几个关键的问题需要解决:

1、数据怎么相对均匀地分片

2、客户端怎么访问到相应的节点和数据

3、重新分片的过程,怎么保证正常服务

4.3.1 架构

Redis Cluster 可以看成是由多个 Redis 实例组成的数据集合。客户端不需要关注数 据的子集到底存储在哪个节点,只需要关注这个集合整体。

以 3 主 3 从为例,节点之间两两交互,共享数据分片、节点状态等信息。

image-20220306222821398

4.3.2 搭建

image-20220306222852883

4.3.3 数据分布

哈希后取模

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

为了解决这个问题,我们又有了一致性哈希算法。

一致性哈希

一致性哈希的原理:

把所有的哈希值空间组织成一个虚拟的圆环(哈希环),整个空间按顺时针方向组 织。因为是环形空间,0 和 2^32-1 是重叠的。

假设我们有四台机器要哈希环来实现映射(分布数据),我们先根据机器的名称或 者 IP 计算哈希值,然后分布到哈希环中(红色圆圈)。

image-20220306222930632

现在有 4 条数据或者 4 个访问请求,对 key 计算后,得到哈希环中的位置(绿色圆圈)。沿哈希环顺时针找到的第一个 Node,就是数据存储的节点。

image-20220306223011973

在这种情况下,新增了一个 Node5 节点,不影响数据的分布。

image-20220306223031811

删除了一个节点 Node4,只影响相邻的一个节点。

image-20220306223106784

一致性哈希解决了动态增减节点时,所有数据都需要重新分布的问题,它只会影响 到下一个相邻的节点,对其他节点没有影响。 但是这样的一致性哈希算法有一个缺点,因为节点不一定是均匀地分布的,特别是 在节点数比较少的情况下,所以数据不能得到均匀分布。解决这个问题的办法是引入虚 拟节点(Virtual Node)。 比如:2 个节点,5 条数据,只有 1 条分布到 Node2,4 条分布到 Node1,不均匀。

image-20220306223234520

Node1 设置了两个虚拟节点,Node2 也设置了两个虚拟节点(虚线圆圈)。 这时候有 3 条数据分布到 Node1,1 条数据分布到 Node2。

image-20220306223303025

4.3.4 客户端重

4.3.5 数据迁移

因为 key 和 slot 的关系是永远不会变的,当新增了节点的时候,需要把原有的 slot 分配给新的节点负责,并且把相关的数据迁移过来。

新增一个节点

redis-cli --cluster add-node 127.0.0.1:7291 127.0.0.1:7292

新增的节点没有哈希槽,不能分布数据,在原来的任意一个节点上执行:

redis-cli --cluster reshard 127.0.0.1:7291

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

4.3.6 高可用和主从切换原理

当 slave 发现自己的 master 变为 FAIL 状态时,便尝试进行 Failover,以期成为新 的master。由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master 节点的过程, 其过程如下:

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 通知其他

Redis Cluster 既能够实现主从的角色分配,又能够实现主从切换,相当于集成了 Replication 和 Sentinal 的功能。

4.3.7 总结

优点:

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