目录
一、单机Redis
1. 问题说明
之前我们在使用Redis的时候,全部使用的是Redis的单机模式。因为单机模式Redis搭建简单、使用方便,利于学习入门。但是在实际使用中,单机Redis存在一些问题需要解决:
-
数据持久化问题
Redis为了提高性能,数据是在内存中存储的。而内存不能持久化存储数据,所以Redis提供了持久化机制
-
并发能力问题
单机Redis的并发能力有限,可以通过主从集群来实现读写分离,从而提高并发能力
-
故障恢复问题
在Redis集群中,一旦某个节点宕机,就必须要手动进行故障转换与恢复。Redis提供了哨兵模式来实现自动故障恢复
-
存储能力问题
无论是主从模式的集群,还是哨兵模式的集群,都没有解决存储能力的扩展问题。Redis提供了分片集群模式,可以很方便的动态扩容
2. 安装Redis
提示:虚拟机里,我们都以root帐号登录,密码是 itcast
提示:虚拟机里,先关闭防火墙,再做后边的操作
-
关闭防火墙:
systemctl stop firewalld
-
防火墙 取消开机自启:
systemctl disable firewalld
-
清理虚拟机里的旧配置
rm -rf ~/0*
1 解压安装Redis【备用】
把资料里的《redis-6.2.4.tar.gz》上传到Linux的/root
目录下
或者直接镜像拉取
执行命令安装redis:
#1. 安装Redis需要的依赖程序包
yum install -y gcc tcl#2. 切换到root用户的家目录
cd ~
#3. 解压Redis程序包
tar -xvf redis-6.2.4.tar.gz
#4. 切换到Redis目录里
cd ~/redis-6.2.4/
#5. 编译并安装Redis。如果此命令不出错,通常就表示安装成功了
make && make install
2 配置Redis
#1. 在root家目录里创建文件夹
mkdir ~/01standalone
#2. 把Redis配置文件拷贝进来
cp ~/redis-6.2.4/redis.conf ~/01standalone/
#3. 切换到~/01standalone/目录里
cd ~/01standalone/
#4. 使用vi编辑redis.conf
vi redis.conf
使用vi修改redis.conf的如下内容,修改之后再保存并退出vi:
# 绑定地址,默认是127.0.0.1,只能在本机访问Redis服务。修改为0.0.0.0则可以在任意IP访问Redis服务
bind 0.0.0.0
# 数据库数量,设置为1
databases 1
3 启动Redis
所有单机问题,我们全在~/01standalone/
目录里操作,使用这个目录里的配置文件
-
启动Redis服务:
redis-server ~/01standalone/redis.conf
-
使用Redis:
redis-cli
,然后就可以使用Redis的命令了 -
关闭Redis服务:
redis-cli shutdown
💡Redis服务安装好以后,可以同时启动多个实例,只要加载对应的配置文件,使用不同的端口即可
3. 小结
Linux里redis的操作:
-
启动redis服务:
redis-server 配置文件路径
-
连接Redis:
redis-cli
-
断开连接:
exit
-
关闭Redis服务:
redis-cli shutdown
二、Redis持久化
1. 持久化机制介绍
所谓持久化,指的是数据的永久保存。Redis是一个内存数据库,它的所有数据都在内存中,所以有极高的读写性能,但是内存中的数据全部是临时的,所以一旦Redis进程结束,所有数据就会清空了。
为了防止这样的问题,Redis提供了持久化机制:
-
RDB模式:快照模式,默认是开启状态的
-
AOF模式:日志模式
注意:在后续的所有演示中,只要修改了配置文件,就必须要重启redis服务
2. RDB模式
RDB,Redis Database Backup file,称为Redis数据快照。当执行RDB持久化时,会把Redis内存中的数据全部都保存到磁盘文件上;当RDB恢复数据时,会读取磁盘文件,把文件里所有的数据恢复到内存中。
快照文件,也称为RDB文件,默认保存在当前运行目录(在哪个目录里启动Redis服务,就保存在哪个目录)
1 RDB执行时机
在以下情况下,会执行RDB快照持久化:
-
执行了
save
命令 -
执行了
bgsave
命令 -
Redis服务关闭时
-
触发自动RDB的条件时
1 save命令
说明
当执行save命令时,Redis会执行一次RDB持久化。但是save命令是一个阻塞式命令:
-
它由Redis主进程执行RDB持久化,在持久化过程中Redis将不能处理客户端的操作,直到RDB执行完毕
-
如果Redis中数据非常多,持久化将会花费比较长的时间,Redis也将会阻塞比较长的时间
-
目前,
save
命令已经很少使用了,通常使用bgsave
代替它
示例
使用redis-cli连接Redis服务之后,执行命令:save
,就会执行一次RDB持久化
[root@ithiema ~]# redis-cli 127.0.0.1:6379> save OK 127.0.0.1:6379>
退出redis-cli,查看一下有没有RDB文件:
127.0.0.1:6379> exit [root@ithiema 01standalone]# ls dump.rdb redis.conf
2 bgsave命令
说明
bgsave,指background save。当执行bgsave
命令时,将会执行一次RDB持久化。
而bgsave是非阻塞的、异步式的:
-
Redis会fork一个子进程,由子进程负责RDB持久化
-
而主进程仍然可以处理客户端的操作,使用体验更好
示例
使用redis-cli连接Redis服务之后,执行命令:bgsave
,就会执行一次RDB持久化
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379>
3 Redis服务关闭
当结束Redis服务时,Redis会先执行一次save命令,把内存中的数据进行RDB持久化。
关闭Redis服务的方式有很多,可以:
-
在redis-server服务进程中,按
ctrl + c
,立即结束redis服务 -
在redis-cli客户端中,执行命令
shutdown
,关闭redis服务 -
或者直接执行Linux命令
redis-cli shutdown
命令
4 RDB自动触发
Redis的RDB模式提供了默认的自动触发机制,相关的配置参数在配置文件redis.conf
中,默认值如下:
-
如果3600秒内有1次数据变更,就执行一次RDB
-
如果300秒内有100次数据变更,就执行一次RDB
-
如果60秒内有10000次数据变更,就执行一次RDB
save 3600 1
save 300 100
save 60 10000
提示:如果写成 save ""
,表示禁用RDB
2 RDB的其它参数
在Redis的配置文件redis.conf中,还有一些RDB相关的参数,我们可以了解一下
rdbcompression yes
dbfilename dump.rdb
dir ./
-
rdbcompression:是否开启RDB文件压缩
如果参数值为yes,Redis将会对rdb文件进行压缩,最终rdb文件会更小
占用磁盘空间更小,但是压缩与解压时会消耗CPU
-
dbfilename:RDB文件名称
自定义RDB文件名称
-
dir:工作路径
RDB文件保存的路径,默认是
./
3 RDB执行原理
默认情况下,Redis服务只有一个进程,由这个进程负责处理客户端的一切操作请求。
当执行bgsave
命令时,Redis会fork一个子进程出来,实现异步的RDB:
-
由子进程负责执行RDB,
-
而主进程继续负责处理客户端的操作请求。
虽然子进程执行RDB持久化的过程中,并不会对主进程造成影响,所以主进程不会阻塞,可以继续处理客户端的操作请求。但是还有一些新问题需要考虑:
-
fork子进程,也需要一定的时间。但这个时间相对于RDB持久化而言,就非常短暂了,只需要几十毫秒多则1秒钟的时间
-
如果子进程执行RDB的过程中,客户端有新的操作改变了数据,为了避免这些新改变的数据对RDB过程造成影响,Redis采用了copy-on-write技术:
-
当主进程执行读操作时,访问共享内存;
-
当主进程执行写操作时,则会拷贝一份数据,执行写操作。
-
3. AOF模式
AOF,Append Only File。也有人称为“日志模式”。当执行AOF持久化时,会把执行的每个数据变更的命令追加保存到磁盘文件里。当AOF恢复数据时,会读取磁盘文件,按顺序依次执行所有的命令,恢复数据。
1 开启AOF
Redis的AOF默认是关闭状态的,如果要开启AOF模式,则需要:
-
修改
redis.conf
配置文件
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"
-
appendonly
:AOF模式的开关。如果值是yes,表示开启;如果是no,表示关闭 -
appendfilename
:AOF文件的名称。默认是appendonly.aof
,可以自定义文件名
2.重启Redis服务
先关闭Redis服务,执行命令:redis-cli shutdown
再重启Redis服务,执行命令:redis-server redis.conf
2 AOF执行时机
开启AOF模式之后,在redis.conf中配置有的AOF持久化执行时机,可通过appendfsync
参数进行配置
#appendfsync always
appendfsync everysec
#appendfsync no
-
如果值为
always
:同步刷盘,每次的写数据的命令,就立即追加到aof文件中 -
如果值为
everysec
:每次的写命令先放到AOF缓冲区,然后以每秒一次的频率,把缓冲区里的命令保存到aof文件 -
如果值为
no
:每次的写命令先放到AOF缓冲区,然后完全由操作系统决定何时 把缓冲区里命令保存到aof文件
三种时机的对比:
注意:只要修改了配置文件,就必须要重启redis服务
刷盘:把缓冲区里的数据存储到磁盘上,称为刷盘。 flush
3 AOF文件重写
1 AOF冗余记录
因为AOF保存的是写命令,类似于日志文件,所以通常情况下AOF日志文件都比RDB文件大,且随着使用时间的推移,AOF文件通常会越来越大,从而导致:
-
磁盘空间的占用越来越大
-
恢复数据的速度越来越慢
主要原因在于,AOF忠实的记录每次写操作的命令,就可能有大量重复的命令;比如对同一key有多次修改操作,每次修改操作都会记录到AOF文件里,而实际上只有最后一次操作命令才有效。假如先后执行以下命令:
set num 1
set num 10
set num 100
set num 1
那么AOF文件里会保存4条命令,实际上只需要最后一条命令就可以了
2 bgrewriteaof重写
手动执行AOF重写
通过在redis-cli中执行bgrewriteaof
命令,可以让AOF文件执行重写:
-
删除无效的命令。例如:
set a A
,set a B
,del a
三个命令,其实全部都可以删除掉 -
合并多余的命令。例如:
自动触发AOF重写
Redis也会在触发阈值时自动去重写AOF文件,阈值的配置在redis.conf
文件中
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
-
auto-aof-rewrite-min-size
:AOF文件必须大于这个值,才可能触发AOF重写 -
auto-aof-rewrite-percentage
:当AOF文件 与 上次重写后的文件对比,超过这个百分比后,会触发AOF重写
4. RDB和AOF对比
RDB和AOF两种持久化模式各有各的优缺点。在实际开发中往往是两者结合使用
5. 小结
Redis的持久化机制:
-
RDB机制
-
如何持久化的:
把内存里所有的数据,保存到磁盘文件上;当redis服务重启时,就从磁盘上加载文件,把数据恢复到内存中
-
什么时候持久化的:
执行save命令时:是一个阻塞式命令,持久化时当前线程会阻塞,影响性能
执行bgsave命令时:是一个非阻塞式命令,会fork一个子进程。由子进程负责RDB持久化,由主进程负责处理客户端的操作命令
redis服务关闭时:当redis服务正常关闭时,会先执行RDB持久化,之后才会关闭服务;
触发redis自动RDB:配置文件里有自动持久化的时机。
-
save 3600 1
-
save 300 100
-
save 60 10000
-
-
bgsave的原理:
在bgsave之前,是由主进程通过页表操作物理内存里的数据
当执行bgsave时:
-
会fork一个子进程,会拷贝主进程里的页表,然后子进程就可以通过页表读取物理内存里的数据,保存到磁盘文件上
-
同时,为了防止子进程RDB过程中,物理内存里的数据被修改:会把物理内存里的数据设置为read-only只读。子进程RDB时,数据就不会被修改
-
如果这时有主进程执行了新的命令要修改数据:物理内存里的数据是只读的,Redis会采用copy-on-write机制,把数据拷贝一个副本,对这个数据副本进行读写操作
-
当子进程RDB结束之后,会丢弃旧版本的数据,保留最新的副本数据
-
-
-
AOF机制
-
如何持久化的:
AOF默认是关闭的,需要开启AOF机制才可以
Redis会把执行所有 数据变更的命令,追加保存到磁盘文件上;当Redis重启恢复数据时,就加载磁盘文件,按顺序执行所有命令
-
什么时候持久化的:
always,同步刷盘。redis每执行完成一个命令之后,都会立即把命令追加保存到磁盘文件上
everysec,每秒刷盘。redis每执行完成一个命令之后,会把命令放到缓冲区里。然后每秒一次 把缓冲区里的命令保存到磁盘文件上
no,由操作决定何时刷盘。redis每执行完成一个命令之后,会把命令放到缓冲区里。操作系统空闲时刷盘
-
AOF文件大,命令冗余的处理:利用AOF重写
手动重写,执行命令 bgrewriteaof
自动重写,根据配置文件里的参数,达到阈值(默认64mb,增长100%)时会自动重写
-
Redis4.0开始,提供了混合持久化(RDB+AOF)
三、Redis主从模式
1. 介绍
单节点的Redis服务支持的并发是有限的:所有客户端的请求全部冲击到仅有的一台服务器上,服务器可能因为压力过大而阻塞不能及时响应。
这时候可以采用主从架构,做到读写分离:多个Redis节点共同提供服务,所有写数据的操作都请求到主服务器,所有读数据的操作都请求到从服务器。读写分离,提升并发能力
2. 搭建Redis主从架构【备用】
1 架构说明
我们搭建的Redis主从集群结构,共包含三个节点。其中一个主节点,两个从节点
我们将会在同一个虚拟机里开启三个Redis实例,模拟主从集群,信息如下:
如图所示:
2 搭建主从集群
要同时启动三个Redis实例,就需要准备三个单独的文件夹、三个单独的配置文件。
#1. 准备一个文件夹02master,把主从集群所有相关的配置全放到这个文件夹里
mkdir ~/02master
#2. 在02master里准备三个文件夹,作为三个redis实例的工作目录
cd ~/02master/
mkdir 6380 6381 6382#3. 把Redis的配置文件,分别拷贝到6380,6381,6382三个文件夹里。
echo 6380 6381 6382 | xargs -t -n 1 cp ~/redis-6.2.4/redis.conf#4. 分别修改6380、6381、6382三个文件夹里的配置文件
# 把端口分别修改为6380、6381、6382
# 把配置文件里的dir,全部修改为各自的工作目录
cd ~/02master
sed -i -e 's/6379/6380/g' -e 's/dir .\//dir \/root\/02master\/6380\//g' -e 's/bind 127.0.0.1 -::1/bind 0.0.0.0/g' 6380/redis.conf
sed -i -e 's/6379/6381/g' -e 's/dir .\//dir \/root\/02master\/6381\//g' -e 's/bind 127.0.0.1 -::1/bind 0.0.0.0/g' 6381/redis.conf
sed -i -e 's/6379/6382/g' -e 's/dir .\//dir \/root\/02master\/6382\//g' -e 's/bind 127.0.0.1 -::1/bind 0.0.0.0/g' 6382/redis.conf#5. 修改每个Redis实例的ip
# 虚拟机本身有多个虚拟网卡,有多个ip地址。为了防止地址混乱,我们直接在配置文件里指定要绑定的ip地址
# 6380、6381、6382三个文件夹里的配置文件都要修改,执行以下命令
cd ~/02master
printf '%s\n' 6380 6381 6382 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.200.136' {}/redis.conf
3 启动集群
为了方便查看每个Redis实例的日志,我们开启三个ssh容器,分别启动3个redis实例。命令如下:
# 第一个Redis实例
redis-server ~/02master/6380/redis.conf
# 第二个Redis实例
redis-server ~/02master/6381/redis.conf
# 第三个Redis实例
redis-server ~/02master/6382/redis.conf
附加:如果想要一键停止所有Redis实例,可以执行以下命令:
printf '%s\n' 6380 6381 6382 | xargs -I{} -t redis-cli -p {} shutdown
4 开启主从关系
到目前为止,三个Redis实例之间还没有任何关系。要配置主从关系,可以使用Redis提供的replicaof
命令(Redis5.0开始)或者slaveof
命令(Redis5.0以前),两个命令效果一致。
主从关系的配置有临时配置和永久配置两种
-
永久生效:修改配置文件,然后重启所有Redis服务
在redis.conf中增加一行配置:
slaveof masterIp masterPort
-
临时生效:使用redis-cli连接Redis服务,执行slaveof命令(Redis实例重启后失效)
slaveof masterIp masterPort
这里为了方便演示,我们使用方式二临时生效,将6380节点设置为master:
1. 连接6381,执行命令
#连接6381实例
redis-cli -p 6381
#设置为6380的从节点
slaveof 192.168.200.136 6380
2. 连接6382,执行命令
#连接6382实例
redis-cli -p 6382
#设置为6380的从节点
slaveof 192.168.200.136 6380
3. 连接6380,查看集群状态
#连接6380实例
redis-cli -p 6380
#查看集群状态
info replication
5 测试
按顺序执行以下操作:
-
使用redis-cli连接6380,执行
set sum 100
-
使用redis-cli连接6381,执行
get num
, 然后再执行set num 101
-
使用redis-cli连接6382,执行
get num
,然后再执行set num 102
结果发现:
-
只有6380这个节点上可以进行写操作
-
6381和6382两个节点上只能进行读操作
3. 主从数据同步原理
1 全量同步
当主从第一次建立连接时,会执行全量同步:将master节点的所有数据都拷贝给slave节点,流程如下:
但是这里有一个问题:Master如何判断 slave是否第一次连接呢?我们需要先了解一个概念:
-
Replication Id:简称replid,由40位十六进制字符组成。每个Master节点启动时都会给自己的数据集生成一个replid,而slave会继承其master的replid。
-
offset:偏移量,是一个数字,是记录的指令的位置,会随着记录在repl_baklog中的数据增多而增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave的数据落后于master,需要更新。
因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据:
-
而slave原本也是一个master,有自己的replid和offset。当第一次变成slave,与master建立连接时,发送的replid和offset是自己的replid和offset。
-
master判断发现slave发送来的replid与自己的不一致,说明这是一个全新的slave,就知道要做全量同步了。
-
master会将自己的replid和offset都发送给这个slave,slave保存这些信息。以后slave的replid就与master一致了。
因此,master判断一个节点是否是第一次同步的依据,就是看replid是否一致。
完整流程描述:
-
slave节点请求增量同步
-
master节点判断replid,发现不一致,拒绝增量同步
-
master将完整内存数据生成RDB,发送RDB到slave
-
slave清空本地数据,加载master的RDB
-
master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
-
slave执行接收到的命令,保持与master之间的同步
2 增量同步
全量同步需要先做RDB,然后将RDB文件通过网络传输个slave,成本太高了。因此除了第一次做全量同步,其它大多数时候slave与master都是做增量同步。例如:slave节点宕机后重连master,就优先判断能否使用增量同步。
什么是增量同步?就是只更新slave与master存在差异的部分数据。如图:
3 repl_backlog原理
什么是repl_backlog
repl_backlog是由Master主节点创建和维护的一个环形缓冲区。正常情况下,Master会把自己执行的所有写命令,也会向repl_backlog缓冲区里写一份;所有Slave执行增量同步时的数据都来自repl_backlog缓冲区。
repl_backlog是一个固定大小的数组,只不过数组是环形,也就是说角标到达数组末尾后,会再次从0开始读写,这样数组头部的数据就会被覆盖。
repl_backlog实现增量复制的过程
1) Master把写命令存储到repl_backlog里
repl_backlog中会记录Redis处理过的写命令日志及offset,包括master当前的offset,和slave已经拷贝到的offset。slave与master的offset之间的差异,就是salve需要增量拷贝的数据了。
2) Slave同步repl_backlog中的命令
随着不断有数据写入,master的offset逐渐变大。
slave也不断的读取repl_backlog中的命令,同步到slave中,追赶master的offset:
3) repl_backlog填满后环绕从头开始
直到repl_backlog数组被完全填满,如果再有新的数据写入,就会覆盖数组中的旧数据。不过,旧的数据只要是绿色的,说明是已经被同步到slave的数据,即便被覆盖了也没什么影响。因为未同步的仅仅是红色部分。
4) Slave落后过多后只能全量同步
但是,如果slave出现网络阻塞,导致master的offset远远超过了slave的offset;如果master继续写入新数据,其offset就会覆盖旧的数据,直到将slave现在的offset也覆盖:
棕色框中的红色部分,就是尚未同步,但是却已经被覆盖的数据。此时如果slave恢复,需要同步,却发现自己的offset都没有了,无法完成增量同步了。只能做全量同步。
注意:repl_backlog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过长,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次进行全量同步
4. 主从同步优化
主从同步可以保证主从数据的一致性,非常重要。
可以从以下几个方面来优化Redis主从就集群:
-
Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
-
在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO
-
适当提高repl_backlog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
-
限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
主从从架构图:
5. 小结
主从集群:解决的问题
-
并发能力问题。由多个节点共同组成集群,并发能力就提升了。特别读的并发能力
-
防止单点故障。只有一个节点的话,一旦节点宕机,整个服务不可用。集群可以防止这样的单点故障,提高可用性
主从集群:角色的划分。一主多从
-
主节点:只有一个,可以提供读和写服务
-
从节点:可以有多个,只提供读数据的服务
-
主从之间需要进行数据同步
主从全量同步:
-
发生在什么时候:一个节点第一次变成slave的时候,先进行一次全量同步
-
全量同步的过程:
第一阶段:建立主从关系
-
slave把自己数据集的id(replication id)发送给master
-
master收到以后判断 slave给的replication id 和自己 replicationid不同:确定slave是第一次连接master
-
master会首先把自己的replication id发送给slave;slave丢弃自己的replication id,接受master replication id
第二阶段:开始全量同步
-
master执行bgsave,生成RDB。把RDB发送给slave
-
slave丢弃自己的所有的旧数据,加载主节点提供的RDB
第三阶段:后续的增量同步
-
在第二阶段全量同步期间,master所执行的新命令会存储到repl_backlog里
-
master在第二阶段结束,会把repl_backlog里的命令发送给slave
-
slave再执行接收到的命令。最终slave的数据和master同步了
-
repl_backlog:
-
是什么:是Master创建并维护的一个环形缓冲区。其实就是一个数组,Master不断把它执行的命令添加到数组里,如果数组满了,就从头开始把旧的数据覆盖掉;slave要从repl_backlog里不断的读取命令,同步到slave里
-
增量同步的过程:
slave向master发请求,要求同步数据,会给master发送自己的replication id,和上次同步的位置offset
master判断replication id和自己的相同,再判断offset和自己master的offset
-
如果slave的offset 与 master的offset 相差超过一圈:就只能全量同步了
-
如果slave的offset 与master的offset 相差不超过一圈:就从slave的offset开始,把后边的所有命令同步给slave,是增量同步
-
-
增量同步:
-
通常是在slave重启,会进行全量同步
-
如果slave节点宕机时间过长,可能就要进行全量同步了
-
主从集群的优化:
-
单个redis节点尽量不要分配太大内存,主从同步时比较慢
-
可以启动无磁盘复制,减少磁盘IO操作
-
提升repl_backlog的大小,减少全量同步的机率和次数
-
如果slave过多,可以采用主-从-从链式结构
四、Redis哨兵模式
1. 介绍
Redis的主从模式,可以保证主从的数据一致性,并且可以实现读写分离,有效提升并发能力。但是主从集群有一个缺陷:当Master宕机之后,需要人工干预进行故障恢复。
这时候,可以引入哨兵模式,实现集群故障的自动恢复
2. 哨兵模式的架构原理
1 哨兵模式的架构
哨兵的作用如下:
-
监控:Sentinel 会不断检查您的master和slave是否按预期工作
-
自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
-
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
2 集群监控原理
Sentinel基于心跳机制监测服务状态,定时(每秒1次)向集群的每个实例发送ping命令:
-
主观下线:如果某sentinel节点发现某实例未在规定时间(通过参数配置)响应,则认为该实例主观下线。
-
客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
3 集群故障恢复原理
选举原则
一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
-
首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
-
然后判断slave节点的slave-priority值(通过参数配置),越小优先级越高,如果是0则永不参与选举
-
如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
-
最后是判断slave节点的runid大小,越小优先级越高(越小表示redis实例启动的越早)。
切换Master
当选出一个新的master后,该如何实现切换呢?
流程如下:
-
sentinel给备选的slave节点发送slaveof no one命令,让该节点成为master
-
sentinel给所有其它slave发送slaveof 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
-
最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
3. 搭建哨兵集群
1 架构说明
这里我们搭建一个三节点形成的Sentinel集群,来监管之前的Redis主从集群。如图
三个Sentinel实例信息如下:
2 准备实例和配置
准备文件夹
要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。
先创建文件夹~/03sentinel
文件夹,然后在~/03sentinel
里创建三个文件夹,名字分别叫s1、s2、s3:
mkdir ~/03sentinel
cd ~/03sentinel/
mkdir s1 s2 s3
准备sentinel配置文件
准备s1实例的配置
切换到s1文件夹里:cd ~/03sentinel/s1
使用创建文件sentinel.conf
: vi sentinel.conf
,添加如下内容:
port 16380
sentinel announce-ip 192.168.200.136
sentinel monitor mymaster 192.168.200.136 6380 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/root/03sentinel/s1"
说明:
-
port 16380
: 当前Sentinel实例的端口号 -
sentinel monitor mymaster 192.168.200.136 6380 2
:指定主节点master的信息-
mymaster
:主节点名称,任意写 -
192.168.200.136 6380
:主节点的ip和端口 -
2
:选举时的quorum
值
-
-
down-after-milliseconds
:哨兵心跳监测的时间间隔 -
failover-timeout
:故障转移的超时失败时间
准备s2和s3实例的配置
将~/03sentinel/s1/sentinel.conf
拷贝到s2和s3两个目录中
cp ~/03sentinel/s1/sentinel.conf ~/03sentinel/s2
cp ~/03sentinel/s1/sentinel.conf ~/03sentinel/s3
修改s2和s3的配置文件,将其端口分别修改为16381、16382
sed -i -e 's/16380/16381/g' -e 's/s1/s2/g' ~/03sentinel/s2/sentinel.conf
sed -i -e 's/16380/16382/g' -e 's/s1/s3/g' ~/03sentinel/s3/sentinel.conf
3 启动
要使用Sentinel,我们必须保证刚才的Redis主从集群是启动运行状态,并且要保证6380是Master节点
如果Redis主从集群未启动,就执行以下命令:
1. 启动三个Redis实例
redis-server ~/02master/6380/redis.conf
redis-server ~/02master/6381/redis.conf
redis-server ~/02master/6382/redis.conf
2. 设置主从关系:把6380设置为master节点
-
redis-cli -p 6381
,然后执行命令slaveof 192.168.200.136 6380
-
redis-cli -p 6382
,然后执行命令slaveof 192.168.200.136 6380
-
redis-cli -p 6380
,然后执行命令查看集群状态info replication
确定6380是master节点,6381和6382是slave节点
为了方便查看日志,我们打开3个ssh客户端,分别启动3个redis实例,启动命令:
# 第1个
redis-sentinel ~/03sentinel/s1/sentinel.conf
# 第2个
redis-sentinel ~/03sentinel/s2/sentinel.conf
# 第3个
redis-sentinel ~/03sentinel/s3/sentinel.conf
4 测试
尝试让master节点6380宕机: redis-cli -p 6380 shutdown
查看sentinel日志。发现已经有了新的master节点:6382
4. RestTemplate访问哨兵集群
在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。
导入资料里的《redis-cluster》工程,然后:
1 添加依赖坐标
添加spring-data-redis起步依赖
最终依赖如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/>
</parent><properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties><dependencies>
<!--Redis起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies><build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2 准备配置文件
spring:
redis:
sentinel:
master: mymaster #主节点的名称。在创建Sentinel集群时指定的
nodes: #Sentinel哨兵的地址
- 192.168.200.136:16380
- 192.168.200.136:16381
- 192.168.200.136:16382
3 配置读写策略
在引导类或者配置类里,添加以下代码,配置Redis集群的读写策略:
/**
* 配置Redis的Sentinel集群读写策略
* ReadFrom.MASTER: 仅从master节点读数据
* ReadForm.REPLICA:仅从slave节点读数据
* ReadForm.MASTER_PREFERRED:优先从Master节点读数据
* ReadFrom.REPLICA_PREFERRED:优先从Slave节点读数据
*/
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
3 测试
创建测试类,读写数据
package com.itheima;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
public class RedisSentinelTest {
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Test
public void test(){
// redisTemplate.opsForValue().set("key::sentinel", "hello, sentinel");
String s = redisTemplate.opsForValue().get("key::sentinel");
System.out.println("s = " + s);
}
}
5. 小结
主从集群存在的问题:故障转移的问题,一旦Master节点宕机,就需要人工干预切换Master主节点。可以增加哨兵解决问题
哨兵模式:在主从集群基础上,增加哨兵集群。哨兵的职责:
-
监控:哨兵会监控主从集群的健康状态,采用的是心跳机制,默认每1条ping一次
主观下线:某个哨兵在规定时间内ping节点,但是没有收到回应,就把节点标记为主观下线
客观下线:超过指定数量的哨兵,都把某个节点标记为主观下线,就是客观下线
-
故障转移:哨兵在发现Master宕机之后,会自动选举挑选新的Master节点。选举的策略
先把上次同步时间过长的slave节点排除掉,没有选举资格
对比节点的slave-priority值。值越小,优先级越高。0表示不参与选举
如果slave-priority相同,对比offset。offset越大,优先级越高。因为offset越大,说明数据和master越接近
如果offset相同,对比runid。runid越小,优先级越高。因为runid越小,说明启动的越早
-
通知:通知主从切换、通知集群状态
通知主从切换:通知新的Master执行 slaveof no one;通知其它所有节点执行 slaveof 新master的ip 新master端口
还会通知整个集群的信息状态(默认10s一次)
五、Redis分片集群
1. 介绍
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
-
海量数据存储问题
-
高并发写的问题
使用分片集群可以解决上述问题
2. 分片集群的架构
分片集群特征:
-
集群中有多个master,每个master保存不同数据
-
每个master都可以有多个slave节点
-
master之间通过ping监测彼此健康状态
-
客户端请求可以访问集群任意节点,最终都会被转发到正确节点
3. 搭建分片集群
1 架构说明
分片集群需要的节点数量较多,这里我们搭建一个最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下:
这里我们会在同一台虚拟机中开启6个redis实例,模拟分片集群,信息如下:
2 准备实例和配置
准备文件夹
创建04cluster文件夹,并在文件夹里准备7380 7381 7382 8380 8381 8382六个文件夹
mkdir ~/04cluster
cd ~/04cluster/
mkdir 7380 7381 7382 8380 8381 8382
准备配置文件
准备7380的配置
-
切换到7380目录:
cd ~/04cluster/7380
-
使用vi编辑文件:
vi redis.conf
, 内容如下
port 7380
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /root/04cluster/7380/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /root/04cluster/7380
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.200.136
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /root/04cluster/7380/run.log
准备其它实例的配置
将7380里的配置文件,拷贝到其它每个目录里
cd ~/04cluster
# 执行拷贝
echo 7381 7382 8380 8381 8382 | xargs -t -n 1 cp ~/04cluster/7380/redis.conf
修改每个目录下的redis.conf,修改其端口:
cd ~/04cluster
# 执行修改
printf '%s\n' 7381 7382 8380 8381 8382 | xargs -I{} -t sed -i 's/7380/{}/g' {}/redis.conf
3 启动所有实例
因为已经配置了Redis后台运行,所以可以直接启动,不需要开多个shell端口。执行以下命令:
cd ~/04cluster
#启动7380 7381 7382 8380 8381 8382 六个Redis服务
printf '%s\n' 7380 7381 7382 8380 8381 8382 | xargs -I{} -t redis-server {}/redis.conf
查看是否成功启动,执行命令:ps -ef | grep redis
。如果看到以下结果,说明6个redis实例都启动成功
如果要关闭所有进程,可以执行命令:
-
方式一:
ps -ef | grep redis | awk '{print $2}' | xargs kill
-
方式二:
printf '%s\n' 7380 7381 7382 8380 8381 8382 | xargs -I{} -t redis-cli -p {} shutdown
4 创建集群
虽然服务已经成功启动,但目前6个Redis实例还是独立的,它们之间没有任何关系。
我们需要执行命令来创建集群。在Redis5.0之前创建集群比较麻烦,5.0之后集群管理命令都集成到了redis-cli中
命令说明
redis5.0之前的命令
Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境:
# 安装依赖
yum -y install zlib ruby rubygems
gem install redis
然后通过命令管理集群:
# 进入redis的src目录
cd ~/redis-6.2.4/src
# 创建集群
./redis-trib.rb create --replicas 1 192.168.200.136:7380 192.168.200.136:7381 192.168.200.136:7382 192.168.200.136:8380 192.168.200.136:8381 192.168.200.136:8382
redis5.0开始的命令
我们使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:
redis-cli --cluster create --cluster-replicas 1 192.168.200.136:7380 192.168.200.136:7381 192.168.200.136:7382 192.168.200.136:8380 192.168.200.136:8381 192.168.200.136:8382
命令说明:
-
redis-cli --cluster
或者./redis-trib.rb
:表示要操作redis集群 -
create
:表示要创建集群 -
--cluster-replicas 1
或者--replicas
:指令集群中每个master的副本个数为1。这样:master节点的数量:节点总数 / (replicas + 1),得到的就是master节点的数量
节点列表中前n个就是master节点,其它是slave节点。这些slave随机分配给不同的master
执行命令创建集群
如果在执行下面的命令创建集群时报错:[ERR] Node 192.168.200.136:7380 is not empty. Either the node already knows other nodes
主要原因可能是:该节点默认生成的配置与历史存储的数据不一致导致的
解决的方法是:
1. 关闭所有redis实例:
printf '%s\n' 7380 7381 7382 8380 8381 8382|xargs -I{} -t redis-cli -p {} shutdown
2. 清除对应节点的dump.rdb、nodes.conf等文件
find / -name nodes.conf | xargs rm -rf
find / -name dump.rdb | xargs rm -rf
3. 然后重启redis实例,再执行创建集群的命令
cd ~/04cluster
#启动7380 7381 7382 8380 8381 8382 六个Redis服务
printf '%s\n' 7380 7381 7382 8380 8381 8382 | xargs -I{} -t redis-server {}/redis.conf
执行以下的命令,创建集群
redis-cli --cluster create --cluster-replicas 1 192.168.150.132:7380 192.168.150.132:7381 192.168.150.132:7382 192.168.150.132:8380 192.168.150.132:8381 192.168.150.132:8382
需要我们确证一下,输入“yes“,就开始创建集群了:
开始创建集群
查看集群状态
redis-cli -p 7380 cluster nodes
5 测试
使用命令连接7380节点:redis-cli -c -p 7380
,做如下操作:
-
存储数据:
set num 10
-
获取数据:
get num
-
再次存储:
set a 1
在使用redis-cli连接分片集群时,必须加上参数-c
,否则操作时可能会出错。示例:
尝试连接7380节点:redis-cli -p 7380
,做如下操作:
-
存储数据:
set num 10
-
获取数据:
get num
-
再次存储:
set a 1
发现报错了:
4. 散列插槽(Hash插槽)
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:
数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
-
key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
-
key中不包含“{}”,整个key都是有效部分
例如:key是num,那么就根据num计算;如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。
提问:如何将一批key固定的保存在同一个Redis实例上呢?
答案:可以给这些数据的key,增加相同的{标识}
。例如这些key都以{typeId}
为前缀
查看key的slot值:cluster keyslot key
5. 集群伸缩
因为Redis的分片集群,数据并没有与Redis节点直接进行绑定,而是:数据与插槽绑定,插槽与Redis节点绑定。这样就可以很方便的进行集群的伸缩,增加或减少Redis节点。
我们通过下面例子,演示一下给集群增加节点,需要如何实现。要求:向集群中添加一个新的master节点,并向其中存储num = 10
-
启动一个新的Redis实例,端口为7383
-
把7383节点添加到之前的集群,并作为一个master节点
-
给7383节点分配插槽,使得这个num可以存储到7383实例
这需要有两大步:
-
添加一个节点到集群中
-
转移插槽
1 添加新节点到集群中
创建7383节点
#创建7383文件夹
mkdir ~/04cluster/7383
#把配置文件拷贝到7383文件夹里
cp ~/04cluster/7380/redis.conf ~/04cluster/7383
#修改配置文件
sed -i s/7380/7383/g ~/04cluster/7383/redis.conf
#启动7383实例
redis-server ~/04cluster/7383/redis.conf
添加到集群
查看redis集群操作帮助: redis-cli --cluster help
执行命令:
#把7383节点添加到集群
redis-cli --cluster add-node 192.168.150.132:7383 192.168.150.132:7380
#查看集群状态
redis-cli -p 7380 cluster nodes
2 转移插槽
查看num的插槽
我们要将num存储到7383节点,因此需要先看看num的插槽是多少:redis-cli -c -p 7380 cluster keyslot 键
我们可以将0~3000插槽,从7380节点移动到7383节点上
转移插槽
转换插槽的命令,操作如下:
1. 建立连接:redis-cli --cluster reshard 192.168.200.136:7380
2. 输入要移动的插槽数量,我们输入 3000
3. 输入目标节点的id(哪个节点要接收这些插槽,就输入哪个节点的id)
我们从刚刚的输出结果中,找到7383节点的id设置过来
4. 从哪个节点里转移出插槽?
输入all
,表示全部。即从现有每个master节点中各转移一部分出来
输入节点id,表示从指定节点中转移出来
输入done
,表示输入完毕了
我们这里从7380节点转移出来一部分,要输入7380节点的id
5. 输入yes
,确认转移
确认结果
执行命令:redis-cli -p 7380 cluster nodes
,可以看到7383节点拥有0~2999插槽,说明转移插槽成功了
6. 故障转移
当master宕机时,Redis的分片集群同样具备故障转移的能力。
接下来给大家演示一下分片集群的故障转换,先确认一下集群的初始状态:
-
7380是master节点,8382是其slave节点
-
7381是master节点,8380是其slave节点
-
7382是master节点,8381是其slave节点
-
7383是master节点,没有slave节点
1 自动故障转移
当master宕机时,分片集群会自动将其slave节点提升为master。
我们直接将7381节点关闭:redis-cli -p 7381 shutdown
,
然后查看集群状态 redis-cli -p 7380 cluster nodes
,发现7381是fail状态,8380已经提升成为master
再次启动7381节点:redis-server 7381/redis.conf
再次查看集群状态:redis-cli -p 7380 cluster nodes
,发现7381节点成为了slave
2 手动故障转移
利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。
这种failover命令可以指定三种模式:
-
缺省:默认的流程,如图1~6歩
-
force:省略了对offset的一致性校验
-
takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见
其流程如下:
我们以7381这个slave节点为例,演示如何手动进行故障转移,让7381重新夺回master:
-
利用redis-cli连接7381这个节点:
redis-cli -p 7381
-
在7381节点上执行
cluster failover
命令 -
重新查看集群状态:
cluster nodes
7. RedisTemplate访问分片集群
RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致:
1)引入redis的starter依赖
2)配置分片集群地址
3)配置读写分离
与哨兵模式相比,其中只有分片集群的配置方式略有差异,如下:
spring:
redis:
cluster:
nodes:
- 192.168.200.136:7380
- 192.168.200.136:7381
- 192.168.200.136:7382
- 192.168.200.136:8380
- 192.168.200.136:8381
- 192.168.200.136:8382
六、大总结
Redis的持久化机制
RDB:快照模式
怎么持久化的:将内存里的数据持久化保存到磁盘文件上;当需要恢复数据时,加载磁盘文件,直接恢复到内存中
何时持久化:
执行save命令:阻塞式命令,即持久化过程中redis不能处理其它操作命令
执行bgsave命令:非阻塞式的命令,持久化过程中不影响redis继续处理其它操作命令
redis服务关闭时:正常关闭时,会先执行一次持久化
触发自动持久化:配置文件里有触发的参数时机
save 3600 1
save 300 100
save 60 10000
bgsave的原理:
在bgsave之前,redis主进程正在处理客户端的操作命令
当执行bgsave时
redis会fork一个子进程,把主进程的页表拷贝到子进程;还会把内存里的数据设置为read-only
子进程负责根据页表读取数据,持久化保存到RDB文件
主进程负责继续处理客户端的操作命令,如果要写数据,不能直接操作read-only的数据,会采用copy-on-write机制,把数据拷贝一个副本,主进程操作这个副本AOF:日志模式
怎么持久化的:把redis执行的所有 写操作 的命令,追加保存到磁盘文件;当需要恢复数据时,加载磁盘文件,依次执行所有命令
何时持久化:
always:同步刷盘。当redis执行完成命令之后,立即把命令追加保存到磁盘文件上
everysec:每秒刷盘。当redis执行完操作命令之后,把命令放到缓冲区里。每秒一次把缓冲区里命令保存到磁盘文件上
no:由操作系统决定何时刷盘。当redis执行完操作命令之后,把命令放到缓冲区里。在操作系统空闲时执行刷盘RDB和AOF的对比:
安全性:AOF更不容易丢失数据;RDB可能丢失数据
文件大小:AOF文件更大,因为有比较多的冗余命令
恢复速度:RDB更快,因为直接加载RDB数据恢复到内存中;而AOF需要读取命令、依次执行所有命令才能恢复
优先级:AOF优先级更高。如果开启了AOF,Redis就采用AOF
Redis主从集群:
-
解决了什么问题:
解决了高并发读的问题:多个节点共同提供服务,并发能力更强
解决了可用性问题:防止单点故障,一个节点宕机,还有其它节点可用
-
主从集群的结构:一主多从
主节点:一个主从集群只能有一个主节点,具备读、写数据的能力
从节点:一个主从集群可以有多个从节点,具备读数据的能力
我们如果要写数据,就操作主节点;主节点数据再同步给从节点;然后我们从从节点读取数据
-
主从同步的过程:
一阶段:确认主从关系
-
slave向master发送同步数据的请求,向master提交自己的replication id 和 offset
-
master判断replication id 和自己的replication id是否相同:
-
如果不同,需要建立主从关系:master会把自己的replication id发送给slave;slave丢弃自己的replication id,接受master传递过来的replication id
-
如果相同,说明之前已经建立过主从关系了,这次判断是要全量同步还是增量同步
如果slave的offset,比master的offset落后一圈:只能进行全量同步
否则:就进行增量同步
-
二阶段:全量同步数据
-
Master会执行bgsave,生成RDB;把RDB传输给slave
-
slave收到RDB之后:丢弃自己的所有的旧数据,加载Master传递过来的RDB数据
三阶段:增量同步数据
-
在二阶段RDB过程中,如果有新的命令,master会把命令存储到repl_backlog里
-
在二阶段结束后,把repl_backlog里的命令发送给slave;slave接收并执行
-
-
repl_backlog原理:
是一个环形缓冲区,其实是一个数组
Master会把执行的写操作命令添加到数组里;如果数组满了,就会从头开始覆盖掉数据
slave根据自己的offset,从repl_backlog里读取尚未同步的命令,执行命令同步数据
如果slave长时间没有进行数据同步(比如宕机时间较长,或者网络断开时间较长):导致未同步的数据被覆盖掉,只能进行全量同步
-
主从集群的优化:
每个redis节点的内存不要设置过大,否则RDB和数据同步耗时较长
可以开启无磁盘复制
可以增大repl_backlog的大小,减少全量同步的机率
如果slave过多,可以采用主-从-从链式结构
哨兵模式:在主从集群基础上,增加哨兵集群
-
哨兵解决了什么问题:
主从集群的故障转移问题,不能自动实现故障转移,必须人工干预
-
哨兵的作用
监控:哨兵会监控主从集群的所有节点健康状态,通过心跳机制,每秒一次ping
-
主观下线:当哨兵发现,某个节点在规定时间内没有回应ping,就把节点标记为主观下线
-
客观下线:当超过规定数量的哨兵都认为某节点主观下线,就是客观下线
故障转移:当发现Master宕机,就会重新选举Master
-
如果slave上次同步的时间太久,直接失去选举资格
-
哪个节点的slave-priority值越小,优先级就越高;0表示不参与选举
-
如果slave-priority值相同,就比较offset。哪个节点的offset越大,优先级越高
-
如果offset相同,就比较runid。哪个节点的runid越小,优先级越高
通知:
-
重新选举之后通知主从集群切换主从关系
通知新的主节点执行 slaveof no one,再通知其它节点 slaveof 新主ip 新主端口
-
通知集群的状态
-
分片集群:
-
分片集群解决了什么问题
解决了主从集群的高并发写的问题。因为主从集群里只有一个master具备写数据的能力
解决了主从集群的海量数据存储问题。因为主从集群里各节点数据相同,如果数据太多,就存不下
-
分片集群的特征:
集群里可以有多个master主节点,每个主节点存储一部分数据
每个master节点可以有多个slave节点,实现高可用
分片集群不需要再有哨兵监控和选举,而是master之间互相心跳监控、实现选举
连接任意一个master,master都会帮我们重定向到正确的master上存取数据
-
hash插槽:
总共有16384个hash插槽,每个master节点负责一部分插槽
当存取某个key时,redis会计算key的hash值:
-
如果key里没有
{}
:crc16算法(key) % 16384
结果就是最终的hash值。根据hash值判断存储到哪个节点 -
如果key里有
{}
:crc16算法({}里的内容)%16384
结果就是最终的hash值。根据hash值判断存储到哪个节点
hash插槽:数据和节点之间没有直接的关联关系,方便进行集群的伸缩与数据的转移
-
-
集群伸缩:
向集群里增加新的节点之后,需要给新的节点分配一些hash插槽
-
故障转移:
自动实现故障转移
手动实现故障转移:在节点上执行
cluster failover
,这个节点就会成为master
Java代码操作Redis集群:
-
添加spring-boot-starter-data-redis
-
配置:
-
主从+哨兵的配置,或者 cluster集群的配置不同
-
再设置读写的策略,建议使用 REPLICA_PREFERED,slave优先读
-
-
操作:仍然是使用RedisTemplate操作Redis集群,和之前学习的没有区别