一、主从复制
1.1 主从复制概念
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
1.2、主从复制的作用
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
- 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
1.3、Redis主从复制的流程
- 若启动一个Slave机器进程,则它会向Master机器发送一个“sync command”命令,请求同步连接。
- 无论是第一次连接还是重新连接,Master机器都会启动一个后台进程,将数据快照保存到数据文件中(执行rdb操作),同时Master还会记录修改数据的所有命令并缓存在数据文件中。
- 后台进程完成缓存操作之后,Maste机器就会向Slave机器发送数据文件,Slave端机器将数据文件保存到硬盘上,然后将其加载到内存中,接着Master机器就会将修改数据的所有操作一并发送给Slave端机器。若Slave出现故障导致宕机,则恢复正常后会自动重新连接。
- Master机器收到Slave端机器的连接后,将其完整的数据文件发送给Slave端机器,如果Mater同时收到多个Slave发来的同步请求,则Master会在后台启动一个进程以保存数据文件,然后将其发送给所有的Slave端机器,确保所有的Slave端机器都正常。
1.4、主从复制的搭建
1.4.1、搭建环境
master | 192.168.152.130 |
slave1 | 192.168.152.129 |
slave2 | 192.168.152.128 |
1.4.2、安装Redis(三台一样)
systemctl stop firewalld
setenforce 0
yum install -y gcc gcc-c++ make
tar zxvf redis-5.0.7.tar.gz -C /opt/
cd /opt/redis-5.0.7/
make
make PREFIX=/usr/local/redis install
cd /opt/redis-5.0.7/utils
./install_server.sh
回车四次,下一步需要手动输入
Please select the redis executable path [] /usr/local/redis/bin/redis-server
ln -s /usr/local/redis/bin/* /usr/local/bin/
1.4.3、master和slave配置
进入配置文件(主从设置不一样):
master:
[root@master ~]# vim /etc/redis/6379.conf
第70行 bind 0.0.0.0 #修改监听地址
第137行 daemonize yes #开启守护进程
第172行 logfile /var/log/redis_6379.log #指定日志文件目录
第264行 dir /var/lib/redis/6379 #指定工作目录
第700行 appendonly yes #开启AOF持久化功能
[root@master ~]# /etc/init.d/redis_6379 restart
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
Starting Redis server...
[root@master ~]# netstat -natp | grep redis
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 29211/redis-server
[root@master ~]#
slave1和slave2:
[root@slave1 ~]# vim /etc/redis/6379.conf
第70行 bind 0.0.0.0 #修改监听端口
第137行 daemonize yes #开启守护进程
第172行 logfile /var/log/redis_6379.log #指定日志文件目录
第264行 dir /var/lib/redis/6379 #指定工作目录
第288行 replicaof 192.168.152.130 6379 #指定同步的master节点ip和端口(添加的配置)
第700行 appendonly yes #开启AOF持久化
[root@slave1 ~]# /etc/init.d/redis_6379 restart
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped
Starting Redis server...
[root@slave1 ~]# netstat -natp | grep redis
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 84735/redis-server
[root@slave1 ~]#
1.4.4、验证
在master上进行输入命令:
[root@master ~]# tail -f /var/log/redis_6379.log
或者是下面这则命令,查看日志文件
[root@master ~]# cat /var/log/redis_6379.log
[root@master ~]# redis-cli info replication
# Replication
role:master
#角色是master
connected_slaves:2
#连接从服务器2个
slave0:ip=192.168.152.128,port=6379,state=online,offset=2226,lag=1
slave1:ip=192.168.152.129,port=6379,state=online,offset=2226,lag=1
master_replid:e5ea3429a75e72b43b814353fa8df3f2ace2351f
#master启动时生成的40位16进制的随机字符串,用来标识master节点
master_replid2:0000000000000000000000000000000000000000
#切换主从的时候master节点标识会有更改(暂时是0)
master_repl_offset:2226
#复制流中的一个偏移量,master处理完写入命令后,会把命令的字节长度做累加记录,统计在该字段。该字段也是实现部分复制的关键字段
second_repl_offset:-1
#无论主从,都表示自己上次主实例repid1和复制偏移量;用于兄弟实例或级联复制,主库故障切换
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:2226
在master上Redis创建键key,在slave上验证
master:
[root@master ~]# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set aaa 123
OK
127.0.0.1:6379> get aaa
"123"
127.0.0.1:6379>
slave1,slave2:
[root@slave1 ~]# redis-cli
127.0.0.1:6379> keys *
1) "aaa"
127.0.0.1:6379> get aaa
"123"
127.0.0.1:6379>
二、哨兵模式
2.1、哨兵概念
哨兵是Redis集群架构中非常重要的一个组件,哨兵的出现主要是解决了主从复制出现故障时需要人为干预的问题
2.2、哨兵模式主要功能
- 集群监控:负责监控Redis的master和slave进程是否正常工作
- 消息通知:如果某个Redis实例有故障,那么哨兵负责发送消息作为告警通知给管理员
- 故障转移:如果master node(master角色)挂掉了,会自动转移到slave node上
- 配置中心:如果故障转移发生了,通知client客户端新的master地址
使用一个或者多个哨兵(Sentinel)实例组成的系统,对redis节点进行监控在主节点出现故障的情况下,能将从节点中的一个从节点角色升级为主节点,进行故障转义,保证系统的可用性
2.3、哨兵们监控整个系统节点的过程
- 哨兵之间相互进行命令连接目的为了在同一频道进行信息共享和监控
- 哨兵们向master发送命令连接和订阅连接(周期性)
- 哨兵10/s向master发送info,iR-M会回应哨兵本节点的信息状态+从节点的位置
- 哨兵收到回复之后,知晓R-S01 R-S02的位置
- 然后再向slaves发送命令连接和订阅连接(周期性) ,以达到监控整个集群的目的
2.4、哨兵模式下的故障迁移
①:主观下线
哨兵(Sentinel)节点会每秒一次的频率向建立了命令连接的实例发送PING命令,如果在down-after-milliseconds毫秒内没有做出有效响应包括(PONG/ LOADING/MASTERDOWN)以外的响应,哨兵就会将该实例在本结构体中的状态标记为SRI_s_DOWN主观下线
②:客观下线
当一个哨兵节点发现主节点处于主观下线状态是,会向其他的哨兵节点发出询问,该节点是不是已经主观下线了。如果超过配置参数quorum个节点认为是主观下线时,该哨兵节点就会将自己维护的结构体中该主节点标记为SRIO DOWN客观下线询问命令SENTINEL is-master-down-by-addr
③:master选举
在认为主节点客观下线的情况下,哨兵节点节点间会发起一.次选举,命令为:SENTINEL is-master-down-by-addr只是runid这次会将自己的runid带进去, 希望接受者将自己设置为主节点。如果超过半数以.上的节点返回将该节点标记为leacer的情况下,会有该leader对故障进行迁移
④:故障转移
在从节点中挑选出新的主节点
通讯正常
优先级排序
优先级相同时选择offset最大的( 最接近master的)
将该节点设置成新的主节点SLAVEOFnoone,并确保在后续的INGO命令时该节点返回状态为master
将其他的从节点设置成从新的主节点的从节点,SLAVEQF命令
将旧的主节点变成新的主节点的从节点
2.5、搭建哨兵
2.5.1、搭建环境
master | 192.168.152.130 |
slave1 | 192.168.152.129 |
slave2 | 192.168.152.128 |
2.5.2、具体配置
基于主从同步文件的修改,修改哨兵配置文件(所有节点都需要修改)
[root@master ~]# vim /opt/redis-5.0.7/sentinel.conf
17 protected-mode no #关闭保护模式
21 port 26379 #Redis哨兵默认的监听端口
26 daemonize yes #开启守护进程
36 logfile "/var/log/sentinel.log" #指定日志存放路径
65 dir /var/lib/redis/6379 #指定数据库存放路径
84 sentinel monitor mymaster 192.168.152.130 6379 2
#指定哨兵节点;2:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移
113 sentinel down-after-milliseconds mymaster 3000
#判定服务器down掉的时间周期,默认30000毫秒 (30秒)
146 sentinel failover- timeout mymaster 180000
#故障节点的最大超时时间为180000 (180秒)
2.5.3、启动哨兵
各服务器先启动主节点在启动从节点
redis-sentinel sentinel.conf &
#使用redis-sentinel启动,再使用sentinel.conf,&:放在在后台启动
[root@master ~]# cd /opt/redis-5.0.7/
[root@master redis-5.0.7]# redis-sentinel sentinel.conf &
[1] 30617
[root@master redis-5.0.7]#
[root@master redis-5.0.7]# redis-cli -p 26379 info sentinel #查看哨兵信息;哨兵端口26379
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.152.130:6379,slaves=2,sentinels=3
[1]+ 完成 redis-sentinel sentinel.conf
[root@master redis-5.0.7]#
[root@slave1 ~]# cd /opt/redis-5.0.7/
[root@slave1 redis-5.0.7]# redis-sentinel sentinel.conf &
[1] 86149
[root@slave1 redis-5.0.7]#
[root@slave2 ~]# cd /opt/redis-5.0.7/
[root@slave2 redis-5.0.7]# redis-sentinel sentinel.conf &
[1] 92431
[root@slave2 redis-5.0.7]#
2.5.4、模拟故障
[root@master redis-5.0.7]# ps -ef | grep "redis"
#查看redis-server的进程号
root 29888 1 0 17:56 ? 00:00:12 /usr/local/redis/bin/redis-server 0.0.0.0:6379
root 30618 1 1 19:08 ? 00:00:02 redis-sentinel *:26379 [sentinel]
root 30663 28876 0 19:11 pts/1 00:00:00 grep --color=auto redis
[root@master redis-5.0.7]#
[root@master redis-5.0.7]#
[root@master redis-5.0.7]# kill -9 29888
#杀死Master 节点_上的redis-server 的进程号
[root@master redis-5.0.7]#
[root@master redis-5.0.7]# ps -ef | grep "redis"
root 30618 1 1 19:08 ? 00:00:03 redis-sentinel *:26379 [sentinel]
root 30673 28876 0 19:12 pts/1 00:00:00 grep --color=auto redis
[root@master redis-5.0.7]#
[root@master redis-5.0.7]# tail -f /var/log/sentinel.log
[root@master redis-5.0.7]#
[root@master redis-5.0.7]# watch -n 1 redis-cli -p 26379 info sentinel
[root@master redis-5.0.7]#
效果如图所示,切换成slave2的ip的地址
查看现在的哨兵信息
三、Cluster集群模式
cluster集群,即Redis Cluster,是Redis 3.0开始引入的分布式存储方案。
3.1、cluster集群的作用
(1)数据分区:数据分区(或称数据分片)是集群最核心的功能。
- 集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加;另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。
- Redis单机内存大小受限问题,在介绍持久化和主从复制时都有提及;例如,如果单机内存太大,bgsave和bgrewriteaof的fork操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出。
(2)高可用:集群支持主从复制和主节点的自动故障转移(与哨兵类似);当任一节点发生故障时,集群仍然可以对外提供服务。
3.2、cluster集群的数据分片
- Redis集群引入了哈希槽的概念
- Redis集群有16384个哈希槽(编号0-16383)
- 集群的每个节点负责一部分哈希槽
- 每个Key通过CRC16校验后对16384取余来决定放置哪个哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作
#以3个节点组成的集群为例:
节点A包含0到5460号哈希槽
节点B包含5461到10922号哈希槽
节点C包含10923到16383号哈希槽
PS:Redis集群的主从复制模型
集群中具有A、B、C三个节点,如果节点B失败了,整个集群就会因缺少5461-10922这个范围的槽而不可以用。
为每个节点添加一个从节点A1、B1、C1整个集群便有三个Master节点和三个slave节点组成,在节点B失败后,集群选举B1位为的主节点继续服务。当B和B1都失败后,集群将不可用
3.3、搭建cluster集群
3.3.1、搭建环境
redis的集群一般需要6个节点,3主3从。方便起见,这里所有节点在同一台服务器上模拟
以端口号进行区分: 3个主节点端口号: 6001/6002/6003, 对应的从节点端口号: 6004/ 6005/ 6006
3.3.2、具体步骤
# 创建节点目录,创建6个节点的工作目录
[root@master ~]# cd /etc/redis/
[root@master redis]# mkdir -p redis-cluster/redis600{1..6}
[root@master redis]# ls redis-cluster/
redis6001 redis6002 redis6003 redis6004 redis6005 redis6006
[root@master redis]#
#创建脚本
[root@master redis]# cd /opt
[root@master opt]# vim redis.sh
[root@master opt]# vim redis.sh
#!/bin/bash
for i in {1..6}
do
cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis600$i
#配置文件 模拟的6台redis
cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis600$i
#登陆命令 登录脚本
done
[root@master opt]# bash -x /opt/redis.sh
#使用脚本将配置文件复制
+ for i in '{1..6}'
+ cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis6001
+ cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis6001
+ for i in '{1..6}'
+ cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis6002
+ cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis6002
+ for i in '{1..6}'
+ cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis6003
+ cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis6003
+ for i in '{1..6}'
+ cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis6004
+ cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis6004
+ for i in '{1..6}'
+ cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis6005
+ cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis6005
+ for i in '{1..6}'
+ cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis6006
+ cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis6006
#查看是否创建成功,目录里面是否存在内容
[root@master opt]# cd /etc/redis/redis-cluster/
[root@master redis-cluster]# ls
redis6001 redis6002 redis6003 redis6004 redis6005 redis6006
[root@master redis-cluster]# ls redis6001
redis-cli redis.conf redis-server
3.3.3、修改配置文件
[root@master redis-cluster]# ls
redis6001 redis6002 redis6003 redis6004 redis6005 redis6006
[root@master redis-cluster]#
[root@master redis-cluster]# cd redis6001
[root@master redis6001]# ls
redis-cli redis.conf redis-server
[root@master redis6001]# vim redis.conf
第69行 bind 127.0.0.1 #注释掉或者不修改,默认监听所有网卡
第88行 protected-mode no #关闭保护模式
第92行 port 6001 #修改监听端口
第136行 daemonize yes #开启守护进程
第699行 appendonly yes #开启AOF持久化
第832行 cluster-enabled yes #取消注释,开启集群功能
第840行 cluster-config-file nodes-6001.conf #取消注释,设置集群名称文件
第846行 cluster-node-timeout 15000 #取消注释,设置集群超时时间
其他五个配置文件除端口号和文件名称外其余改动相同,复制redis6001至redis6002-6006
步骤:
[root@master redis6001]# ls
redis-cli redis.conf redis-server
[root@master redis6001]# cp redis.conf ../redis6002/
cp:是否覆盖"../redis6002/redis.conf"? y
[root@master redis6001]# cp redis.conf ../redis6003/
cp:是否覆盖"../redis6003/redis.conf"? y
[root@master redis6001]# cp redis.conf ../redis6004/
cp:是否覆盖"../redis6004/redis.conf"? y
[root@master redis6001]# cp redis.conf ../redis6005/
cp:是否覆盖"../redis6005/redis.conf"? y
[root@master redis6001]# cp redis.conf ../redis6006/
cp:是否覆盖"../redis6006/redis.conf"? y
[root@master redis6001]#
#逐个修改里面两个内容
#第92行 port 端口
#第840行 cluster-config-file nodes-6001.conf 设置集群名称文件
[root@master redis6003]# cd ..
[root@master redis-cluster]# cd redis6002
[root@master redis6004]# vim redis.conf
[root@master redis6004]#
3.3.4、启动服务
可以手动启动六次或者写入脚本执行脚本:
手动启动六次:
[root@master redis-cluster]# ls
redis6001 redis6002 redis6003 redis6004 redis6005 redis6006
[root@master redis-cluster]# cd redis6001/
[root@master redis6001]# redis-server redis.conf
32495:C 09 Aug 2021 22:04:43.499 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
32495:C 09 Aug 2021 22:04:43.500 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=32495, just started
32495:C 09 Aug 2021 22:04:43.500 # Configuration loaded
[root@master redis6001]#
或者是执行脚本启动:
vim /opt/redis_start.sh ##根据对应配置文件启动redis
#!/bin/bash
for d in {1..6}
do
cd /etc/redis/redis-cluster/redis600$d
redis-server redis.conf
done
bash -x /opt/redis_start.sh
查看一下端口信息:
[root@master redis6006]# ps -ef | grep redis
root 30618 1 0 19:08 ? 00:01:19 redis-sentinel *:26379 [sentinel]
root 32496 1 0 22:04 ? 00:00:00 redis-server 127.0.0.1:6001 [cluster]
root 32518 1 0 22:07 ? 00:00:00 redis-server 127.0.0.1:6002 [cluster]
root 32524 1 0 22:07 ? 00:00:00 redis-server 127.0.0.1:6003 [cluster]
root 32531 1 0 22:07 ? 00:00:00 redis-server 127.0.0.1:6004 [cluster]
root 32546 1 0 22:07 ? 00:00:00 redis-server 127.0.0.1:6005 [cluster]
root 32552 1 0 22:07 ? 00:00:00 redis-server 127.0.0.1:6006 [cluster]
root 32557 28876 0 22:08 pts/1 00:00:00 grep --color=auto redis
[root@master redis6006]#
3.3.5、加入群集
六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点;
下面交互的时候需要输入yes才可以创建;-replicas 1表示每个主节点有一个从节点
[root@master redis6006]# cd
[root@master ~]#
[root@master ~]# redis-cli --cluster create 127.0.0.1:6001 127.0.0.1:6002 127.0.0.1:6003 127.0.0.1:6004 127.0.0.1:6005 127.0.0.1:6006 --cluster-replicas 1
3.3.6、验证集群是否成功
[root@master ~]# redis-cli -p 6001 -c #加-c参数,节点之间就可以互相跳转
127.0.0.1:6001> cluster slots #查看节点的哈希槽编号范围
1) 1) (integer) 10923
2) (integer) 16383 #哈希槽编号范围
3) 1) "127.0.0.1"
2) (integer) 6003 #主节点的ip和端口号
3) "5473c012c260bb8c4dd731686ad7298e201cafe6"
4) 1) "127.0.0.1"
2) (integer) 6006 #从节点的ip和端口号
3) "87c7beb7c1eaa37cf6c4e7ec575aba5bd55b8406"
2) 1) (integer) 5461
2) (integer) 10922
3) 1) "127.0.0.1"
2) (integer) 6002
3) "2eb0a1b657aba09f5c3df9d9e81477ec76b0e97a"
4) 1) "127.0.0.1"
2) (integer) 6005
3) "a1fa093e2c5cb57b32ec01af9c2b8c168be2b4ca"
3) 1) (integer) 0
2) (integer) 5460
3) 1) "127.0.0.1"
2) (integer) 6001
3) "fe3164114a7c15cdca2ba83d5904ddf3e1559e16"
4) 1) "127.0.0.1"
2) (integer) 6004
3) "d613737ffcb866b63aec37a0907df5991121eac1"
127.0.0.1:6001>
127.0.0.1:6001>
127.0.0.1:6001>
127.0.0.1:6001> set abc 123 #新建的键,验证是否会分配到指定哈希槽
-> Redirected to slot [7638] located at 127.0.0.1:6002
OK
127.0.0.1:6002> cluster keyslot abc #查看哈希槽编号
(integer) 7638
127.0.0.1:6002>