一、单机

1、部署

(1)安装

$ wget https://download.redis.io/releases/redis-6.2.6.tar.gz
$ tar xzf redis-6.2.6.tar.gz
$ cd redis-6.2.6
$ make PREFIX=/usr/local/redis-6.2.6 install
$ cp redis.conf /usr/local/redis-6.2.6

(2)运行
修改redis.conf中daemonize设置为yes。
运行redis:
bin/redis-server redis.conf
运行客户端:
bin/redis-cli
关闭redis服务端:
在客户端中执行shutdown

[root@192-168-253-100 redis-6.2.6]# bin/redis-server redis.conf 
[root@192-168-253-100 redis-6.2.6]# bin/redis-cli 
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> shutdown
not connected> 

2、说明

单机模式运行,读写操作都在同一个节点上,一般用于开发和测试,如果用于生产环境的话,一般都是请求并发量非常低,数据量非常少,且这些数据不太重要,允许丢失,这个时候的redis类似于抽离出来的HashMap。

二、主从复制

redis22

1、配置

在从节点上,增加下面配置,指向主节点即可。
replicaof 127.0.0.1 6379

2、原理

redis23
(1)如果slave首次连接master,那么master会把内存中的数据写入到rdb文件,然后把整个文件发给slave,slave把接收到的rdb文件保存到磁盘后,再加载到内存中。
(2)如果master采用的是无磁盘化复制的的话(repl-diskless-sync yes),那么master将直接把rdb文件保存在内存中,然后发给slave。
(3)master和slave都保存着backlog文件,用于断点续传,如果slave宕机后重启了,那么slave会发送slave offset给master,master从offset之后发送数据给slave。
(4)主从复制的过程采用的是异步复制的方式。
(5)slave不会主动过期key,当master的key过期之后,master在清理过期key采用的时候del的方式,然后del命令同步给slave。

3、说明

主从复制的方式,一般用于数据热备,当主节点宕机之后,通过运维的方式把从节点切为主节点,保证数据不丢失。此外主从模式也通常用于读写分离,由于redis作为缓存中间件,通常写少读多,因此可以多部署几个从节点来提升系统的QPS,但由于不支持高可用,主节点宕机会导致写入缓存失败。

三、哨兵

redis24

1、配置

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
#sentinel auth-pass mymaster 123456

说明一下:
(1)sentinel monitor mymaster 127.0.0.1 6379 2
表示sentinel监控127.0.0.1 6379节点,并命名为mymaster,判断节点宕机需要2个sentinel,这里的数量一般是(N/2 + 1),N表示sentinel总数。sentinel可以同时监控多个redis集群,通过mymaster来区分。
(2)sentinel down-after-milliseconds mymaster 60000
down-after-milliseconds指定了sentinel认为主节点宕机的毫秒数,如果sentinel在指定的时间内没有收到PING命令的回复,或者收到一个错误的回复,那么sentinel就认为该主节点宕机,这个时候状态标记主节点为主动下线(SDOWN),如果有多个sentinel任务主节点为主动下线,这个时候主节点的状态转换为客观下线(ODOWN),这个时候才会执行故障转移。
(3)sentinel failover-timeout mymaster 180000
failover-timeout指定了故障主节点恢复的毫秒数,如果在指定时间内还未恢复,则sentinel在下次选取主节点的时候,排除该节点为可用的节点。那么在后续再探测是否恢复,如果恢复了则把它作为从节点加入到Sentinel的监控中。
(4)sentinel parallel-syncs mymaster 1
表示同时从新的主节点同步数据的从节点个数
(5)sentinel auth-pass mymaster 123456
如果主节点设置了密码,则需要指定对应的密码。

2、启动

方式一:redis-sentinel sentinel.conf
方式二:redis-server sentinel.conf --sentinel

3、测试

手动kill掉主节点127.0.0.1:6379,然后观察从节点127.0.0.1:6379的变化,可以看出状态从slave提升到master。

redis25
redis26

4、sentinel执行过程

sentinel执行故障转移主要涉及两点:分别是选举leader sentinel和选取master redis。

(1)选举leader sentinel
采用raft算法进行leader sentinel,其核心思想就是在同一个时期内,通过少数服从多数的原则,选举出一个leader。什么叫多数?就是数量超过总数一半以上的,也就是 n / 2 + 1,这也就是在允许宕机一个sentinel节点的情况下,要求sentinel节点数量最少要配置3个的原因。
那么为什么要选举leader sentinel呢?因为是由它来执行选取master redis和故障转移。

(2)选取master redis
(a)先剔除掉不可用的slave redis,包括
A. 被标记为SDOWN/ODOWN或者最后一次回复PING命名的时间超过5秒的
B. 与master redis断开连接的时间超过down-after-milliseconds 10倍以上的。
(b)从剩下的slave redis节点中,挑选出复制偏移量(replication offset)的从节点为新的master redis,如果存在多个相同偏移量的从节点,则选id最小的从节点。

(3)一次故障转移的执行过程:
(a)发现master redis进入ODOWN状态。
(b)选举leader sentinel。
(c)选出一个slave redis成为master redis。
(d)向被选中的slave redis发送SLAVE ON ONE命令,让它升级为master。
(e)通过发布订阅功能,将更新后的配置传播给其他sentinel,其他sentinel对自己的配置进行更新。
(f)向已经下线master redis的其他slave redis节点发送 SLAVEOF host port,让他们去复制新的master redis。
(g)当所有的slave redis开始复制时,leader sentinel完成这次故障转移任务。

5、说明

哨兵模式对主从模式的一种升级,其实redis解决高可用的一种解决方案。其本质上还是主从,也就是存储的瓶颈在于一个节点。

之前介绍的主从模式,如果主节点宕机了,那么需要运维人员手动将从节点升级为主节点,再修改应用程序配置,重启应用程序,整个过程非常耗时,而且会导致服务不可用的时间较长。那么哨兵模式主要是为了解决上述问题,也就是主节点宕机了,哨兵会自动执行故障转移,通过哨兵充当服务发现的角色,向应用程序返回主节点地址。整个过程无需运维人员参与,导致服务不可用的时间较短。

四、Cluster集群

1、搭建

(1)配置

port 7001
pidfile /var/run/redis_7001.pid
logfile "/usr/local/redis/logs/redis_7001.log"
dir /usr/local/redis/data/7001

cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 15000

说明一下:
A. cluster-enabled yes
开启集群
B. cluster-config-file nodes-7001.conf
每个集群节点都有的一个配置文件,有Redis自动创建和更新。
C. cluster-node-timeout 15000
集群节点在指定的时间内不可达,则表示该节点是为失败状态。

(2)执行create操作
bin/redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1

以下可选:
添加主节点
bin/redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001

添加从节点
bin/redis-cli --cluster add-node 127.0.0.1:7008 127.0.0.1:7007 --cluster-slave --cluster-master-id 7f605f8b6c970f4b40abd79ef4be66514a930d8d

对槽进行reshard
bin/redis-cli --cluster reshard 127.0.0.1:7001
redis27
(3)测试
redis28

2、原理

(1)槽(slot)
redis29
redis把数据划分为16384个槽(slot),在通过redis-cli(5.0版本之前是redis-trib.rb)创建集群时,会根据master节点的数量对16384个槽进行均分,每个master节点上都会各自保存着持有哪些槽。
客户端在写入数据的时候,会根据CRC16(key)进行出hash值,然后让按16384取模,则出对应的slot,如果当前执行的redis-cli不持有该slot,则redis会执行重定向。
redis30
此外,如果新加入master节点,则需要手动执行reshard操作,否则新加入的节点将不持有任何slot,另外,删除节点之前也需要先执行reshard之后再删除,确保所持有的slot转移给其他节点,如果直接删除,slot丢失则整个集群不可用,我们在搭建集群的时候,如果一个master节点以及对应的所有slave节点都宕机了,那么redis集群将不可用。

(a)为什么是16384个槽(slot)?
https://github.com/redis/redis/issues/2576
根据CRC16(key)计算出来的值有65536个值,也就是值分布在0 - 65535,那么redis不为什么不按65536取模而是按16384呢?
A. 每个节点都会存储slot信息,也就是持有哪些slot,而持有的方式是通过bitmap的方式,且redis cluster是无中心化架构,需要通过通信的方式把slot信息同步告知给其他节点,那么如果按照65536个slot来计算,通信的时候需要携带的信息为:65536 ÷ 8 ÷ 1024 = 8kb,每次通信需要携带8kb数据,太耗带宽。
B. 作者认为一个redis集群,节点不会超过1000个,因此slot数设置为16384,通信的时需要携带的数据为16384 ÷ 8 ÷ 1024 = 2kb , 算是一个比较平衡的数,因为不会太耗带宽,也能让每个节点分到较多的slot。

(2)slot迁移过程

[root@192-168-253-100 redis]# bin/redis-cli --cluster reshard 127.0.0.1:7001
....... 一些节点信息
How many slots do you want to move (from 1 to 16384)? 1
What is the receiving node ID? 38fb14ec237f75b9da4c91d6385178c6af82e104 # 127.0.0.1:7008节点ID
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1: b225590fd683ad95cb575dbfd1d121be82a8d418 # 127.0.0.1:7001节点ID
Source node #2: done

Ready to move 1 slots.
  Source nodes:
    M: b225590fd683ad95cb575dbfd1d121be82a8d418 127.0.0.1:7001
       slots:[0-8517],[10923-13977] (11573 slots) master
       2 additional replica(s)
  Destination node:
    M: 38fb14ec237f75b9da4c91d6385178c6af82e104 127.0.0.1:7008
       slots: (0 slots) master
  Resharding plan:
    Moving slot 0 from b225590fd683ad95cb575dbfd1d121be82a8d418
Do you want to proceed with the proposed reshard plan (yes/no)? yes
Moving slot 0 from 127.0.0.1:7001 to 127.0.0.1:7008: 

上面是我们在新增加一个节点或者删除节点的reshard操作,也就是迁移slot的操作。
那么redis cluster执行slot迁移的过程是怎样的呢?
首先redis cluster通过rax树来存放slot与key的映射关系,我们可以通过以下命令来操作
cluster keyslot key # 查询某个key存在哪个slot
cluster getkeysinslot slot索引 N # 获取某个slot下的N个key
cluster couintkeysinslot slot索引 # 获取某个slot下的key数量

具体执行slot迁移步骤如下:
A. 对目标节点发送cluster setslot importing命令,让目标节点准备导入slot。
B. 对源节点发送cluster setslot migrating命令,让源节点准备导出slot。
C. 源节点执行cluster getkeysinslot命令,获取count个key数据
D. 源节点执行migrate <keys …>命令,把key迁移到目标节点
E. 重复执行C-D,直到所有的key都迁移到目标节点
F. 向集群所有的主节点发送cluster setslot node命令,通知slot分配给目标节点。

(3)gossip
对于分布式集群来说,通常需要存储一些元数据,比如节点的ip、状态等等,通常有两种存储机制:分散式和集中式。
a.分散式机制
redis31
分散式机制将元数据存储在节点上,不同节点之间进行不断的通信来维护元数据的变更和一致性。

b. 集中式机制
redis32
集中式机制将元数据统一存储在外部中间件,比如Zookeeper进行统一管理。

分散式和集中式对比

模式 优点 缺点
分散式 不需要外部中间件,元数据存储在节点上,数据更新压力分散 数据更新有延迟,节点之间需要不断的通信
集中式 元数据统一管理,数据更新及时,节点之间不需要来回通信,降低带宽 需要部署外部中间件,更新压力全部集中在外部节点上,如果中间件宕机会影响集群运行

redis33
redis cluster采用的是分散式机制才存储元数据,采用的协议是gossip。
Gossip 协议,就像流言蜚语一样,利用一种随机、带有传染性的方式,将信息传播到整个网络中,并在一定时间内,使得系统内的所有节点数据一致。
Redis Cluster 中的每个节点都维护一份自己视角下的当前整个集群的状态,主要包括:

  • 当前集群状态
  • 集群中各节点所负责的 slots信息,及其migrate状态
  • 集群中各节点的master-slave状态
  • 集群中各节点的存活状态及怀疑Fail状态

Redis Cluster 的节点之间会相互发送多种消息,较为重要的如下所示:

  • MEET:通过「cluster meet ip port」命令,已有集群的节点会向新的节点发送邀请,加入现有集群,然后新节点就会开始与其他节点进行通信;
  • PING:节点定时向集群中其他节点发送 ping 消息,消息中带有自己的状态,还有自己维护的集群元数据,和部分其他节点的元数据;
  • PONG: 节点用于回应 PING 和 MEET 的消息,结构和 PING 消息类似,也包含自己的状态和其他信息,也可以用于信息广播和更新;
  • FAIL: 节点 PING 不通某节点后,会向集群所有节点广播该节点挂掉的消息。其他节点收到消息后标记已下线。
打赏
支付宝 微信
上一篇 下一篇