redis分布式部署方式
- redis主从模式
- sentinel哨兵模式
- redis集群模式
Redis分布式的优点
- 提升性能,部署多台redis服务分摊压力,实现负载均衡。
- 高可用,避免单点故障,带来的问题。
- 可扩展性,redis所有的数据都存放在内存中,如果数据量大,很容易受到硬件的限制。升级硬件性价比低,所以需要一种水平扩展的方法。
redis主从复制
1.主从复制配置
Redis主从配置非常简单,只要在slave节点的redis.conf配置中开启如下配置
#配置master的ip + port
replicaof 192.168.0.101 6379
也可以在redis启动的时候指定从属于某台服务器,如下
./redis-server --slaveof 192.168.0.101 6379
还可以在redis客户端中进行配置,如下
redis> slaveof 192.168.0.101 6379
注意:从节点只读,不能进行写操作。
2.主从复制的原理
Redis主从复制可以分为两类:
- 全量复制:就是在节点第一次连接到master的时候,需要全部数据。
- 增量复制:如已经连接master的节点,由于网络问题断开或者宕机,导致缺失一部分数据。
2.1、全量复制
slave与master建立连接
1、slave节点启动时(或者执行slaveof命令时),会在自己本地保存master节点的信息,包括master node 的host和ip。
2、slave节点内部有个定时任务replicationCron,每隔1秒钟检查是否有新的master node要连接和复制。源码replication.c 3132行。
如果发现有master节点,就跟master节点建立连接。如果连接成功,从节点就为连接连理一个专门处理复制工作的文件事件处理器负责后续的复制工作。为了让主节点感知到slave节点的存活, slave节点定时会给主节点发送ping请求。
建立连接以后,就可以同步数据了,这里也分成两个阶段。
数据同步
如果是新加入的slave节点,那就需要全量复制。master通过bgsave命令在本地生成一份RDB快照,将RDB快照文件发给slave节点(如果超时会重连,可以调大repl-timeout的值)。
如果slave节点自己有数据的话,需要先清除旧数据。
如果master节点生成RDB文件期间,接收到写命令;则在RDB文件同步完成后,进行增量同步。
2.2、增量复制
增量复制是通过类似aof的方式,来同步命令,在slave上执行,从而实现数据同步。
slave通过master_repl_offset记录的偏移量,来记录增量同步数据的位置。master_repl_offset参数如下图:
无盘复制介绍
无盘复制是master节点生成RDB文件不保存到磁盘而是直接通过网络发送给从节点。适用于机器磁盘性能差,但网络带宽比较富裕的场景。
开启方式如下
repl-diskless-sync=no
3.3、主从复制的不足
redis主从复制,只解决了数据备份和一部分性能问题,但是没有解决高可用的问题。
sentinel哨兵模式
1.哨兵的搭建方式
2.哨兵原理
2.1.哨兵的工作流程
让我们跟着下图先学习下,哨兵的工作流程吧
- sentinel之间项目监控,没有主从之分,确保高可用。
- 每台sentinel都监控所有的redis节点,sentinel之间唯一的联系是通过监控相同的master。
- redis客户端,直接和sentinel集群连接就可以。
2.2.服务下线感知
主观下线
Sentinel默认以每秒钟1次的频率向Redis服务节点发送PING命令。如果在指定时间内没有收到有效回复,Sentinel 会将该服务器标记为下线。
由这个参数控制:
# sentinel.conf
sentinel down-after-milliseconds <master-name><millisecond>
客观下线
但是,只有你发现 master下线,并不代表master真的下线了。也有可能是你自己的网络出问题了。所以,这个时候第一个发现 master下线的Sentinel节点会继续询问其他的Sentinel节点,确认这个节点是否下线,如果多数Sentinel节点都认为master下线, master才真正确认被下线。
2.3.故障转移
2.3.1.选出sentinel的Leader
Redis 的选举和故障转移都是由Sentinel完成的。问题又来了,既然有这么多的Sentinel节点,由谁来做故障转移的事情呢?
故障转移流程的第一步就是在Sentinel集群选择一个Leader,由Leader完成故障转移流程。Sentinle通过Raft算法,实现Sentinel选举。
Raft是一个共识算法(consensus algorithm)。Spring Cloud的注册中心解决方案Consul也用到了Raft协议。
Raft的核心思想:先到先得,少数服从多数。
Raft算法演示:http://thesecretlivesofdata.com/raft
总结:
Sentinle的Raft算法和Raft 论文略有不同。
1、 master客观下线触发选举,而不是过了election timeout时间开始选举。
2、Leader并不会把自己成为Leader的消息发给其他Sentinel。其他Sentinel等待Leader 从 slave选出master后,
检测到新的master 正常工作后,就会去掉客观下线的标识,从而不需要进入故障转移流程。
2.3.2.故障转移
Redis选出master节点的规则
1、如果与哨兵连接断开的比较久,超过了某个阈值,就直接失去了选举权。
2、如果拥有选举权,那就看谁的优先级高,这个在配置文件里可以设置( replica-priority 100),数值越小优先级越高。
3、如果优先级相同,就看谁从master 中复制的数据最多(复制偏移量最大),选最多的那个
4、如果复制数量也相同,就选择进程id最小的那个。
2.4.Sentinel功能总结
- 监控: Sentinel会不断检查主服务器和从服务器是否正常运行。
- **通知: **如果某一个被监控的实例出现问题,Sentinel可以通过API发出通知。
- 自动故障转移(failover): 如果主服务器发生故障,Sentinel可以启动故障转移过程。把某台服务器升级为主服务器,并发出通知。
- 配置管理: 客户端连接到Sentinel,获取当前的Redis主服务器的地址。
2.5.哨兵机制的不足
哨兵机制解决了分布式redis的高可用问题,但是只能单点写,没有解决水平扩容的问题。
Redis Cluster
Redis Cluster是在Redis 3.0的版本正式推出的,用来解决分布式的需求,同时也可以实现高可用。跟Codis不一
样,它是去中心化的,客户端可以连接到任意一个可用节点。
数据分片有几个关键的问题需要解决:
1、数据分布问题
2、客户端怎么访问到相应的节点和数据
3、重新分片的过程,怎么保证正常服务
1.redis集群搭建
2.数据分布问题
Redis 既没有用哈希取模,也没有用一致性哈希,而是用虚拟槽来实现的。
Redis 创建了16384个槽(slot),每个节点负责一定区间的slot。比如Node1负责0-5460,Node2负责5461-
10922,Node3负责10923-16383。
对象分布到Redis节点上时,对key 用CRC16算法计算再%16384,得到一个slot的值,数据落到负责这个slot的
Redis节点上。
Redis的每个master节点都会维护自己负责的slot。用一个 bit序列实现,比如:序列的第0位是1,就代表第一个
slot是它负责;序列的第1位是0,代表第二个slot不归它负责。
查看key属于那个slot:
redis>cluster keyslot test1
**注意:**key 与slot的关系是永远不会变的,会变的只有slot和Redis节点的关系。
如何让相关的数据落在同一个节点上?
比如有些multi key操作是不能跨节点的,例如用户2673的基本信息和金融信息?
在key里面加入**{hash tag}**即可。Redis 在计算槽编号的时候只会获取f之间的字符串进行槽编号计算,这样由于
上面两个不同的键,0里面的字符串是相同的,因此他们可以被计算出相同的槽。
redis> set a{test}a 1
redis> set a{test}b 1
redis> set a{test}c 1
redis> set a{test}d 1
redis> set a{test}e 1
3.客户端怎么访问到相应的节点和数据
比如说在7291端口Redis的redis-cli客户端上操作:
127.0.0.1:7291> set test 300
(error) MOVED 6918 127.0.0.1:7292
服务端返回MOVED,也就是根据key计算出来的slot不归7291端口管理,而是归7293端口管理,服务端返回
MOVED告诉客户端去7293端口操作。
这个时候更换端口,用redis-cli-p 7293操作,才会返回OK。或者用./redis-cli -c -p port
的命令。
这样客户端需要连接两次。Jedis 等客户端会在本地维护一份slot–node的映射关系,大部分时候不需要重定
向,所以叫做smart jedis(需要客户端支持)。
4.数据迁移(重新分配槽)
因为key和slot的关系是永远不会变的,当新增了节点的时候,需要把原有的 slot分配给新的节点负责,并且把
相关的数据迁移过来。
# 添加7297节点到集群中
redis-cli --cluster add-node 127.0.0.1:7297 127.0.0.1:7291
# 给7297节点重新分配槽
redis-cli --cluster reshard 127.0.0.1 7297
输入需要分配的哈希槽的数量(比如500),和哈希槽的来源节点(可以输入all或者id)。
5.高可用主从切换原理
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可
能会有多个slave,从而存在多个slave竞争成为master节点的过程,其过程如下:
- slave 发现自己的master变为FAIL。
- 将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST 信息。
- 其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack。
- 尝试failover的 slave 收集FAILOVER_AUTH_ACK。
- 超过半数后变成新Master。
- 广播Pong通知其他集群节点。
总结:Redis Cluster既能够实现主从的角色分配
,又能够实现主从切换
,相当于集成了Replication和Sentinel的功能。
6.总结
Redis Cluster特点:
-
无中心架构。
-
数据按照slot存储分布在多个节点,节点间数据共享,可动态调整数据分布。
-
可扩展性,可线性扩展到1000个节点(官方推荐不超过1000个),节点可动态添加或删除。
-
高可用性,部分节点不可用时,集群仍可用。通过增加Slave做standby数据副本,能够实现故障自动
failover,节点之间通过gossip 协议交换状态信息,用投票机制完成Slave到 Master的角色提升。
-
降低运维成本,提高系统的扩展性和可用性。