2024.11.7- Redis的主从复制集群
7.1 Redis的主从复制
7.1.1 简介
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
主从复制的作用主要包括:
数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
7.1.2 搭建步驟
1)说明
1. 如果有密碼策略,那麽从节点需要主节点的密码,如果想要启动哨兵机制,也需要密码策略 2. 正常情况下,master和slave应该分布在不同的机器上。 三台机器: 192.168.100.101 youcai01 6379 master 192.168.100.102 youcai02 6379 slave 192.168.100.103 youcai03 6379 slave 3. 使用持久化混合模式 4. 防火墙一定要关闭 # 如果只有一台机器,可以使用不同的配置文件和port以及不同的持久化的位置即可。
2)搭建步骤
步骤1: 修改youcai01、youcai02、youcai03的配置文件redis.conf(可以使用克隆的方式)
[root@youcai01 ~]# vim /usr/local/redis/bin/redis.conf #注释 只能本地连接 #bind 127.0.0.1 #端口号 port 6379 #设置后台启动 daemonize yes #3 默认开启保护模式,如果没有设置密码或者没有 bind 配置,我只允许在本机连接我,其它机器无法连接。 protected-mode no #密码策略 requirepass 123456 #连接master的密码, 在两个slave上配置 master宕机后,slave--》master masterauth 123456 #pid文件的位置: 进程id保存的位置 pidfile "/var/run/redis_6379.pid" #启动服务的日志级别: DEBUG,INFO.... loglevel notice #启动服务器的日志文件位置: 空字符串是STDOUT,默认打印到屏幕上 logfile "/var/log/redis.log" #======== RDB全量持久化设置 save 3600 1 300 100 60 10000 # 文件名 dbfilename dump.rdb # rdb持久化的位置 dir "/usr/local/redis/mydata" #======== AOF增量持久化设置 appendonly yes appendfilename "appendonly.aof" #RDB和AOF两个持久化混合使用, 默认就是这个设置 aof-use-rdb-preamble yes
步骤2)启动三个服务
提前写了一个启动或关闭的服务脚本: 注意,关闭的IP要对应上自己的IP,
[root@youcai03 ~]# vim /usr/local/redis/bin/myRedisServer.sh #!/bin/bash PATH=/usr/local/redis/bin case $1 in start) $PATH/redis-server $PATH/redis.conf echo "---redis服务已经启动---" ;; stop) $PATH/redis-cli -h 192.168.100.103 -a 123456 shutdown echo "---redis服务已经关闭---" ;; esac
在三台机器上运行: [root@youcai01 ~]# myRedisServer.sh start [root@youcai02 ~]# myRedisServer.sh start [root@youcai03 ~]# myRedisServer.sh start 最好是查看一下进程: ps -ef | grep redis
步骤3)连接三台服务
[root@youcai01 ~]# redis-cli -h youcai01 -a 123456 -p 6379 [root@youcai02 ~]# redis-cli -h youcai02 -a 123456 -p 6379 [root@youcai03 ~]# redis-cli -h youcai03 -a 123456 -p 6379
步骤4)查看各个服务的状态
info replication 正常情况下:看到的都是master
步骤5)配从不配主
在slave机器上,配置,语法如下:
slaveof/replicaof master-host master-port # replicaof/slaveof 这两个命令二选一即可,功能一样
临时配置:在客户端里使用如下指令
102机器上配置:slaveof youcai01 6379 103机器上配置:slaveof youcai01 6379
永久配置:配置文件里配置
530 # network partition replicas automatically try to reconnect to masters 531 # and resynchronize with them. 532 # replicaof/slaveof 这两个命令二选一即可,功能一样 533 replicaof youcai01 6379
步骤6)测试
slave上只能读,不能写,写的话要在master进行,当然master也可以进行读操作
缺点:
一旦master宕机,slave并不能自动选出一个代表作为master,需要人工干预,很麻烦。
断开关系
slaveof no one 表示我切断与master的关系。
7.1.3 主从复制的原理
首先进行全量同步(全量复制)
当我们配置好主从同步的时候,由于之前没有进行过任何同步,所以首先会进行一次全量数据同步到从库。
-
建立连接
Slave从库会主动和Master主库进行通信,发送psync 命令,该命令会捎带两个参数过去给Master,第一个参数是主库ID(runID),redis 在启动的时候,都会为自己生成一个ID,第二个是Slave复制Maser数据的偏移量offset。 Slave第一次和Master进行通信,由于一开始不知道Master的ID,所以传递了 ?; 由于是第一次复制,offset 传递 -1 表示第一次要进行全量复制。 接着Master接收到了Slave传递过来的命令以及相应的参数,一看是? 和 -1 ,那么就知道这个Slave要进行全量的复制,Master会给Slave 发送一个 fullresync 命令,告诉Slave接下来要开始全量复制,并带上自己的 ID,Slave 接收到这两个参数后会保存起来。
-
全量复制
master节点收到sync命令后会执行bgsave, fork 子进程开始保存快照(即RDB持久化,主从复制会触发RDB),同时收集所有接收到的用于修改数据集命令缓存起来,master节点执行RDB持久化后,master将rdb快照文件和缓存的命令发送到所有slave,来进行一次完全同步 而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中(slave自己原有的数据会提前清空),从而完成复制初始化
-
心跳持续,保持通信
repl-ping-replica-period 10 master发出PING包的周期,默认是10秒
进入平稳,增量复制
master 继续将新的所有收集到的修改命令自动一次传给slave,完成同步
从机下线,重连续传
master 会检查backlog里面的offset,master和slave都会保存一个复制的offset并带有一个masterId(runID) offset 是保存在backlog 中的。master只会把已经复制的offset后面的数据赋值给slave,类似断点续传
缺点
-
由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
-
master宕机,slave不能自动切换成master,需要手动
7.2 哨兵模式
哨兵的四个功能
主从监控:监控主从redis库运行是否正常 消息通知:哨兵可以将故障转移的结果发送到客户端,客户端通过连接哨兵来获得当前Redis服务的主节点地址 故障转移:如果master异常,则会进行主从切换,将其中一个slave作为新master
使用建议
-
哨兵节点的数量应为多个,哨兵本身应该集群,保证高可用
-
哨兵节点的数量应该是奇数个
-
各个哨兵节点的配置应该一致
-
如果哨兵节点部署在Docker等容器里,要注意端口的正确映射
-
哨兵集群+主从复制,并不能保证数据零丢失
说明)
搭建三个哨兵 192.168.100.101 192.168.100.102 192.168.100.103
步骤1)拷贝一份哨兵配置文件到bin目录下
[root@youcai01 redis]# cp ./sentinel.conf ./bin/ [root@youcai01 redis]# cd bin/ [root@youcai01 bin]# ll -rw-r--r--. 1 root root 14700 11月 4 13:48 sentinel.conf
步骤2)修改配置文件
[root@youcai01 ~]# vim /usr/local/redis/bin/sentinel.conf protected-mode no port 26379 #设置后台启动, 想要查看信息,可以去日志文件中查看 daemonize yes pidfile /var/run/redis-sentinel.pid # 如果设置了具体的日志路径,那么前台进程的滚动信息都在日志文件中, 可以设置成后台进程,来解放命令行 logfile "/var/log/sentinel.log" dir /usr/local/redis/tmp #设置要监控的redis master,2表示最少有几个哨兵认可客观下线,同意故障迁移的法定票数 sentinel monitor mymaster 192.168.100.101 6379 2 #sentinel访问master密码 sentinel auth-pass mymaster 123456
步骤3)剩下的两台机器,也是这样的配置
[root@youcai01 bin]# scp /usr/local/redis/bin/sentinel.conf youcai02:/usr/local/redis/bin/ [root@youcai01 bin]# scp /usr/local/redis/bin/sentinel.conf youcai03:/usr/local/redis/bin/
步骤4)启动哨兵
注意,主从机器的配置中也要添加
masterauth 123456
先恢复主从机器,使用info replication查看是否正确
myRedisServer.sh start myRedisServer.sh start myRedisServer.sh start
然后启动哨兵,演示自动切换吧,
[root@youcai01 bin]# redis-sentinel /usr/local/redis/bin/sentinel.conf [root@youcai02 bin]# redis-sentinel /usr/local/redis/bin/sentinel.conf [root@youcai03 bin]# redis-sentinel /usr/local/redis/bin/sentinel.conf
演示故障转移
将master杀死, 稍等片刻,查看哨兵日志,应该会发现某一个slave变成了master.
哨兵的工作方式
Sentinel的工作方式: 1):每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令。 2):如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。 3):如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。 4):当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 。 5):在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令 。 6):当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次 。 7):若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。 若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
选举原理
1. 先看优先级,谁高谁当master(数字越小,优先级越高) 736 # By default the priority is 100. 737 replica-priority 100 2. 优先级一样的话,就看偏移量offset,谁的数据最新,谁就当master 3. offset一样的话,runid,谁的最小,谁当master
客观下线时:选举哨兵中的一个领导者,并由该领导者节点进行去通知slave进行failover(故障迁移)
7.3 Redis的集群
7.3.1 简介
1. Redis的集群模式,指的是有多个Master,注意:Master可以有0到多个slave。 2. 集群节点之间的通信机制:ping-pong通信 3. 客户端在连接集群时,如果是写操作,只需要连接上任意一个master即可,如果是读操作,只需要连接集群上的任意一个节点即可(slave或者master) 4. 数据存在集群中的槽中,槽的数量是固定的,16384个。槽是有编号的:0-16383,数据调用key与16384取余,余数就是槽号。 HASH_SLOT = CRC16(key) mod 16384 5. 集群的不可用情况: -- 半数以上的master宕机,集群不可用 -- master和对应的slave都宕机了,集群不可用 3-master 3-slave 注意: --槽的编号之间不能断开。 --槽的计算会将数据保存的很平均,不会产生一个槽满一个槽空的情况。 生产环境中,每个master至少要有一个slave。
7.3.2 集群搭建
1)说明
1. redis在搭建集群时,版本不同所需要的环境不同。 2. redis3.0版本,对ruby版本环境没要求 redis4.x版本,需要ruby环境高于2.2.2 # ruby -v 查询ruby的版本 redis5.x版本,内置了ruby,不需要操作ruby环境 基于上述情况:我们用redis7.2.6来演示redis集群的搭建, 192.168.100.101 master 7001 slave 7002 192.168.100.102 master 7001 slave 7002 192.168.100.103 master 7001 slave 7002
2)搭建步骤
步骤1)上传、解压、编译、安装维护六个实例的目录
[root@youcai01 ~]# tar -zxvf redis-7.2.6.tar.gz -C /usr/local/ [root@youcai01 ~]# cd /usr/local/redis-7.2.6 [root@youcai01 ~]# ln -s /usr/local/redis-7.2.6 /usr/local/redis [root@youcai01 ~]# cd /usr/local/redis/ [root@youcai01 redis]# make && make install PREFIX=/usr/local/redis [root@youcai01 redis]# cp redis.conf ./bin/redis7001.conf [root@youcai01 redis]# cp redis.conf ./bin/redis7002.conf [root@youcai01 redis]#
步骤2)修改配置文件redis7001.conf……..
先拷贝一个配置文件,修改下面的参数 [root@youcai01 redis]# vim ./bin/redis7001.conf
#启动后台进程 daemonize yes #修改pid文件的位置 pidfile /var/run/redis_7001.pid logfile "/var/log/redis7001.log" #端口号 port 7001 #持久化的位置 dir "/usr/local/redis/mydata" # 开启aof appendonly yes # 密码策略 requirepass 123456 masterauth 123456 #解开注释,启用集群模式 cluster-enabled yes #集群的配置文件 cluster-config-file nodes-7001.conf #集群的连接超时时间 cluster-node-timeout 5000
再复制修改
[root@youcai01 bin]# cp redis7001.conf redis7002.conf [root@youcai01 bin]# vim redis7002.conf <======= 修改了四个地方 与端口号有关的地方 [root@youcai01 bin]# scp redis700* youcai02:$PWD [root@youcai01 bin]# scp redis700* youcai03:$PWD
步骤3)启动六个实例,默认都是master状态,还不是集群
[root@youcai01 bin]# /usr/local/redis/bin/redis-server /usr/local/redis/bin/redis7001.conf #检查进程 [root@youcai01 bin]# ps -ef| grep redis root 44546 1 0 15:27 ? 00:00:00 /usr/local/redis/bin/redis-server *:7001 [cluster] root 44606 1 0 15:27 ? 00:00:00 /usr/local/redis/bin/redis-server *:7002 [cluster]
步骤4)创建集群:
# --cluster-replicas 1 表示为每个master创建一个slave节点 [root@youcai01 mydata]# redis-cli -a 123456 --cluster create --cluster-replicas 1 192.168.100.101:7001 192.168.100.102:7001 192.168.100.103:7001 192.168.100.101:7002 192.168.100.102:7002 192.168.100.103:7002
-------------------到此为止,安装成功,愉快的玩耍吧----------------------
连接集群客户端操作:
redis-cli -c -p 7001 注释:-c 表示连接集群中的某一个节点 #查看节点信息 cluster nodes #查看集群信息 cluster info #查看当前节点主从关系 info replication #查看指定key所在的slot cluster keyslot name1
如果安装过程中出错了,怎么办
1. 找到配置的位置,修改相应的错误地方 2. 关闭或杀死各个实例 3. 删除各个实例里的持久化文件(dump.rdb,appendonly.aof)和集群配置文件(nodes-700x.conf) 4. 重启各个实例的服务器 5. 再次创建关联。
7.2.3 代码演示
package com.qf.redis.day01 import java.util import redis.clients.jedis.{HostAndPort, JedisCluster} object _08ClusterConnectDemo { def main(args: Array[String]): Unit = { //创建一个集群,存储集群的实例 val sets = new util.HashSet[HostAndPort]() sets.add(new HostAndPort("qianfeng01",7001)) sets.add(new HostAndPort("qianfeng01",7002)) sets.add(new HostAndPort("qianfeng01",7003)) //创建JedisCluster对象, 就是一个客户端 val cluster = new JedisCluster(sets) //设置kv对象 cluster.set("user1","zhangdasan") cluster.hset("user2","username","zhangxiaosan") cluster.lpush("scores","10","20","30") cluster.sadd("names","xiaozhang","xiaohei","xiaohong") cluster.close() } }