目录
3.2 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):
2 然后在配置文件application.yml中指定sentinel相关信息:
3 例子:向集群中添加一个新的master节点,并向其中分配3000插槽
3.2 将tmp目录下的redis配置文件拷贝到7004目录了
例子:在7002这个slave节点执行手动故障转移,成为master地位
单点Redis的问题
1数据丢失问题
实现Redis数据持久化
2并发能力问题
搭建主从集群,实现读写分离
3存储能力问题
搭建分片集群,利用插槽机制实现动态扩容
4故障恢复问题
利用Redis哨兵,实现健康检测和自动恢复
单机安装Redis
环境:CentOS7 redis版本:6.2.4
1 首先需要安装Redis所需要的依赖
yum install -y gcc tcl
2 下载安装包 Download | Redis
3 上传到服务器并解压
例如,我放到了/tmp目录:
解压缩:
tar -xvf redis-6.2.4.tar.gz
解压后:
进入redis目录:
cd redis-6.2.4
4 运行编译命令:
make && make install
如果没有出错,应该就安装成功了。
5 然后修改redis.conf文件中的一些配置:
# 绑定地址,默认是127.0.0.1,会导致只能在本地访问。修改为0.0.0.0则可以在任意IP访问
bind 0.0.0.0
# 数据库数量,设置为1
databases 1
# redis 密码 刚安装模式是无密码
requirepass redisPassword
# 让redis后台运行
daemonize yes
6 启动Redis:
redis-server redis.conf
7 停止redis服务:
redis-cli shutdown
Redis持久化
RDB持久化
也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。
快照文件称为RDB文件,默认是保存在当前运行目录。
save和bgsave
save:
Reids save命令执行一个同步保存操作(主进程执行),将当前Redis实例的所有数据快照(snapshort)已RDB文件的方式保存到磁盘
Redis停机时会执行一次RDB。
bgsave:
bgsave执行后,会立刻返回OK,Redis 会fork一个子进程,原来的redis主进程继续执行后续操作,新fork的子进程负责将数据保存到磁盘,然后退出
Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:
save m n 自动触发bgsave; m 代表多少秒内 n 代表多少个key被修改 则执行bgsave
# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
#save "" 则表示禁用RDB
save 900 1
save 300 10
save 60 10000
RDB的其它配置也可以在redis.conf文件中设置:
# 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱
rdbcompression yes
# RDB文件名称
dbfilename dump.rdb
# 文件保存的路径目录 默认是保存在当前运行目录。
dir ./
save与bgsave的对比:
- save同步阻塞主进程,只有等save完后成,才能进行新操作
- basave 是fork的子进程,非阻塞,等执行完后会通知主进程,然后关闭子进程
RDB的缺点
RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险
fork子进程、压缩、写出RDB文件都比较耗时
注意
RDB 写入数据到磁盘 都是生成新的RDB文件替换旧的RDB文件
AOF持久化 (追加文件)
Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件
1 开启AOF
AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:
# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"
2 设置AOF命令记录频率
AOF的命令记录的频率也可以通过redis.conf文件来配:
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
配置项 | 刷盘时机 | 优点 | 缺点 |
Always | 同步刷盘 | 可靠性高,几乎不丢数据 | 性能影响大 |
everysec | 每秒刷盘 | 性能适中 | 最多丢失1秒数据 |
no | 操作系统控制 | 性能最好 | 可靠性较差,可能丢失大量数据 |
3 重写AOF文件 (bgrewriteaof)
因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。
3.1 手动重写
3.2 配置重写阈值
Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置:
# AOF文件比上次文件 增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
# AOF文件体积最小多大以上才触发重写
auto-aof-rewrite-min-size 64mb
注意
AOF重写是开启一个新进程后台写入(异步执行)
RDB与AOF的对比
RDB | AOF | |
持久化方式 | 定时对整个内存做快照 | 记录每一次执行的命令 |
数据完整性 | 不完整,两次备份之间会丢失 | 相对完整,取决于刷盘策略 |
文件大小 | 会有压缩,文件体积小 | 记录命令,文件体积很大 |
宕机恢复速度 | 很快 | 慢 |
数据恢复优先级 | 低,因为数据完整性不如AOF | 高,因为数据完整性更高 |
系统资源占用 | 高,大量CPU和内存消耗 | 低,主要是磁盘IO资源 但AOF重写时会占用大量CPU和内存资源 |
使用场景 | 可以容忍数分钟的数据丢失,追求更快的启动速度 | 对数据安全性要求较高常见 |
Redis主从并实现读写分离
集群架构
搭建主从架构
本次搭建是在同一台服务上启动三个redis实例来搭建
一台master:
192.168.150.101:7001
两台slave:
192.168.150.101:7002
192.168.150.101:7003
1 准备实例和配置
1.0 在同一台服务器上启动多个redis实例 且互不干扰
只需要创建多个新的配置文件即可 指定不同的端口号 令exe开启时加载不同的配置文件即可
不需要单独复制多分redis的文件
1.1 创建目录
要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录
我们创建三个文件夹,名字分别叫7001、7002、7003:
# 进入/tmp目录
cd /tmp
# 创建目录
mkdir 7001 7002 7003
1.2 修改配置
因为之前搭建了单机redis 并且开起了AOF持久化
所以这儿需要将 redis-6.2.4/redis.conf文件,将其中的持久化模式改为默认的RDB模式,AOF保持关闭状态。(若没有开启,即默认持久化就可(redis的默认持久化就是RDB))
# 开启RDB
# save ""
save 3600 1
save 300 100
save 60 10000
# 关闭AOF
appendonly no
1.3 拷贝配置文件到每个实例目录
然后将redis-6.2.4/redis.conf文件拷贝到三个目录中(在/tmp目录执行下列命令):
# 方式一:逐个拷贝
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003
# 方式二:管道组合命令,一键拷贝
echo 7001 7002 7003 | xargs -t -n 1 cp redis-6.2.4/redis.conf
1.4 修改每个实例的端口、工作目录
修改每个文件夹内的配置文件,将端口分别修改为7001、7002、7003,将rdb文件保存位置都修改为自己所在目录(在/tmp目录执行下列命令):
sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf
1.5 修改每个实例的声明IP
虚拟机本身有多个IP,为了避免将来混乱,我们需要在redis.conf文件中指定每一个实例的绑定ip信息(大部分都是本机ip,redis服务在那台服务器上 ip就是那台服务器上的ip),格式如下:
# redis实例的声明 IP
replica-announce-ip 192.168.150.101
每个目录都要改,我们一键完成修改(在/tmp目录执行下列命令):
# 逐一执行
sed -i '1a replica-announce-ip 192.168.150.101' 7001/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7002/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7003/redis.conf
# 或者一键修改
printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.150.101' {}/redis.conf
因为这儿三个实例都是部署在同一台服务器上的 所以 声明的ip都是同一个
2 启动redis
# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf
2.2 如果要一键停止
可以运行下面命令:
printf '%s\n' 7001 7002 7003 | xargs -I{} -t redis-cli -p {} shutdown
3 开启主从关系
现在三个实例还没有任何关系,要配置主从可以使用replicaof 或者slaveof(5.0以前)命令。
有临时和永久两种模式:
3.1 修改配置文件(永久生效)
在redis.conf中添加一行配置:slaveof <masterip> <masterport>
3.2 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):
slaveof <masterip> <masterport>
注意:在5.0以后新增命令replicaof,与salveof效果一致。
4 这里我们为了演示方便,使用方式二。
通过redis-cli命令连接7002,执行下面命令:
# 连接 7002
redis-cli -p 7002
# 执行slaveof
slaveof 192.168.150.101 7001
通过redis-cli命令连接7003,执行下面命令:
# 连接 7003
redis-cli -p 7003
# 执行slaveof
slaveof 192.168.150.101 7001
然后连接 7001节点,查看集群状态:
# 连接 7001
redis-cli -p 7001
# 查看状态
info replication
结果:
5 测试结果
执行下列操作以测试:
-
利用redis-cli连接7001,执行
set num 123
-
利用redis-cli连接7002,执行
get num
,再执行set num 666
-
利用redis-cli连接7003,执行
get num
,再执行set num 888
可以发现,只有在7001这个master节点上可以执行写操作,7002和7003这两个slave节点只能执行读操作。
主从数据同步原理
主从第一次同步是全量同步
master如何判断slave是不是第一次来同步数据
Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据
全量同步的流程
1 slave节点请求增量同步
2 master节点判断replid,发现不一致,拒绝增量同步
3 master将完整内存数据生成RDB,发送RDB到slave
4 slave清空本地数据,加载master的RDB
5 master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
6 slave执行接收到的命令,保持与master之间的同步
注意:
主从第一次同步是全量同步
slave重启后同步,则可能执行增量同步也可能是全量同步
repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。
因为 repl_baklog 是一个闭环 offset 就是这个闭环里的值
当此闭环还为走完的时候 通过offset能在此闭环里能找到正确的增量数据,这时就执行增量同步
当此闭环已经走完一圈 并超过当初slave的点时,虽然看到增量数据是slave-master这段的数据 实际是 maseter-slave-master这段的数据,这时就做全量同步
优化Redis主从就集群
1 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
2 Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
3 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
4 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结 构,减少master压力
主-从-从链式结构
总结:
简述全量同步和增量同步区别?
全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。
增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave
什么时候执行全量同步?
slave节点第一次连接master节点时
slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
什么时候执行增量同步?
slave节点断开又恢复,并且在repl_baklog中能找到offset时
Redis哨兵
哨兵的作用和原理
哨兵结构
哨兵的作用
监控:Sentinel 会不断检查您的master和slave是否按预期工作
自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
服务状态监控
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下 线。
客观下线:若超过指定数量(quorum:sentinel.conf里配置)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。(sentinel实例的quorum 个都链接不上某redis 就认为给redis实例客观下线)
选举新的master
一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
最后是判断slave节点的运行id大小,越小优先级越高。
如何实现故障转移
当选中了其中一个slave为新的master后(例如slave1),故障的转移的步骤如下:
sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
总结
Sentinel的三个作用是什么?
监控
故障转移
通知
Sentinel如何判断一个redis实例是否健康?
每隔1秒发送一次ping命令,如果超过一定时间没有相向则认为是主观下线
如果大多数sentinel都认为实例主观下线,则判定服务下线
故障转移步骤有哪些?
首先选定一个slave作为新的master,执行slaveof no one
然后让所有节点都执行slaveof 新master
修改故障节点配置,添加slaveof 新master
搭建哨兵集群
1 哨兵集群结构:
这里我们搭建一个三节点形成的Sentinel集群,来监管之前的Redis主从集群。如图:
三个sentinel实例信息如下:
s1 192.168.150.101 27001
s2 192.168.150.101 27002
s3 192.168.150.101 27003
2 准备sentinel实例和配置
要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。
2.1 创建文件夹
我们创建三个文件夹,名字分别叫s1、s2、s3:
# 进入/tmp目录
cd /tmp
# 创建目录
mkdir s1 s2 s3
如图:
2.2 修改sentinel配置
然后我们在s1目录创建一个sentinel.conf文件,添加下面的内容:
port 27001
sentinel announce-ip 192.168.150.101
sentinel monitor mymaster 192.168.150.101 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/tmp/s1"
解读:
port 27001
:是当前sentinel实例的端口- sentinel announce-ip 192.168.150.101 :声明sentinel实例的ip地址
sentinel monitor mymaster 192.168.150.101 7001 2
:指定主节点信息
sentinel monitor
:sentinel 监听mymaster
:主节点名称,自定义,任意写192.168.150.101 7001
:主节点(master)的ip和端口2
:选举master时的quorum值 (当超过2时就认为redis的服务客观下线)- down-after-milliseconds mymaster 5000 slave与master断开最长超时时间 默认
- failover-timeout mymaster 60000 slave故障恢复的时间 默认
只需要指定主节点信息即可 sentinel会自己去redis集群里去获得其它slave的信息
然后将s1/sentinel.conf文件拷贝到s2、s3两个目录中(在/tmp目录执行下列命令):
# 方式一:逐个拷贝
cp s1/sentinel.conf s2
cp s1/sentinel.conf s3
# 方式二:管道组合命令,一键拷贝
echo s2 s3 | xargs -t -n 1 cp s1/sentinel.conf
修改s2、s3两个文件夹内的配置文件,将端口分别修改为27002、27003:
sed -i -e 's/27001/27002/g' -e 's/s1/s2/g' s2/sentinel.conf
sed -i -e 's/27001/27003/g' -e 's/s1/s3/g' s3/sentinel.conf
3 启动redis-sentinel
# 第1个
redis-sentinel s1/sentinel.conf
# 第2个
redis-sentinel s2/sentinel.conf
# 第3个
redis-sentinel s3/sentinel.conf
RedisTemplate的哨兵模式
1 在pom文件中引入redis的starter依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2 然后在配置文件application.yml中指定sentinel相关信息:
spring:
redis:
sentinel:
master: mymaster # 指定master名称
nodes: # 指定redis-sentinel集群信息
- 192.168.150.101:27001
- 192.168.150.101:27002
- 192.168.150.101:27003
3 配置主从读写分离
匿名内部类格式
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
return new LettuceClientConfigurationBuilderCustomizer(){
@Override
public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder
clientConfigurationBuilder){
clientConfigurationBuilder.readFrom(ReadFrom,REPLICA_PREFERRED):
}
};
}
或
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:
MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
REPLICA:从slave(replica)节点读取
REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master
4 调用
@RestController
public class HelloController {
@Autowired
private StringRedisTemplate redisTemplate;
@GetMapping("/get/{key}")
public String hi(@PathVariable String key) {
return redisTemplate.opsForValue().get(key);
}
@GetMapping("/set/{key}/{value}")
public String hi(@PathVariable String key, @PathVariable String value) {
redisTemplate.opsForValue().set(key, value);
return "success";
}
}
Redis分片集群
分片集群结构
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
1 海量数据存储问题
2 高并发写的问题
使用分片集群可以解决上述问题,分片集群特征:
集群中有多个master,每个master保存不同数据
每个master都可以有多个slave节点
master之间通过ping监测彼此健康状态
客户端请求可以访问集群任意节点,最终都会被转发到正确节点
最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下:
搭建分片集群
这里我们会在同一台虚拟机中开启6个redis实例,模拟分片集群,信息如下:
192.168.150.101 | 7001 | master |
192.168.150.101 | 7002 | master |
192.168.150.101 | 7003 | master |
192.168.150.101 | 8001 | slave |
192.168.150.101 | 8002 | slave |
192.168.150.101 | 8003 | slave |
1 准备实例和配置
如果配置了之前的redis主从模式 哨兵模式 请删除之前的7001 7002 7003 这几个目录,
再重新创建7001、7002、7003、8001、8002、8003目录:
# 进入/tmp目录
cd /tmp
# 删除旧的,避免配置干扰
rm -rf 7001 7002 7003
# 创建目录
mkdir 7001 7002 7003 8001 8002 8003
在/tmp下准备一个新的redis.conf文件,内容如下:
port 6379
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /tmp/6379/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /tmp/6379
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.150.101
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /tmp/6379/run.log
将这个文件拷贝到每个目录下:
# 进入/tmp目录
cd /tmp
# 执行拷贝
echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf
修改每个目录下的redis.conf,将其中的6379修改为与所在目录一致:
# 进入/tmp目录
cd /tmp
# 修改配置文件
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf
2 启动 6个redis实例
因为已经配置了后台启动模式,所以可以直接启动服务:
# 进入/tmp目录
cd /tmp
# 一键启动所有服务
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf
通过ps查看状态:
ps -ef | grep redis
发现服务都已经正常启动:
2.1如果要关闭所有进程
可以执行命令:
ps -ef | grep redis | awk '{print $2}' | xargs kill
或者(推荐这种方式):
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown
3 创建集群
虽然服务启动了,但是目前每个服务之间都是独立的,没有任何关联。
我们需要执行命令来创建集群,在Redis5.0之前创建集群比较麻烦,5.0之后集群管理命令都集成到了redis-cli中。
3.1Redis5.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 /tmp/redis-6.2.4/src
# 创建集群
./redis-trib.rb create --replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003
3.2 Redis5.0以后
我们使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:
redis-cli --cluster create --cluster-replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003
命令说明:
redis-cli --cluster
或者./redis-trib.rb
:代表集群操作命令create
:代表是创建集群--replicas 1
或者--cluster-replicas 1
:指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1)
得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master
运行后的样子:
这里输入yes,则集群开始创建:
4 查看集群状态:
redis-cli -p 7001 cluster nodes
5 测试
尝试连接7001节点,存储一个数据:
# 连接
redis-cli -p 7001
# 存储数据
set num 123
# 读取数据
get num
# 再次存储
set a 1
结果悲剧了:
集群操作时,需要给redis-cli
加上-c
参数才可以:
redis-cli -c -p 7001
这次可以了:
散列插槽
16384个插槽
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:
数据key与插槽绑定
数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
key中不包含“{}”,整个key都是有效部分
例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。
总结:
Redis如何判断某个key应该在哪个实例?
将16384个插槽分配到不同的实例
根据key的有效部分计算哈希值,对16384取余
余数作为插槽,寻找插槽所在实例即可
如何将同一类数据固定的保存在同一个Redis实例?
这一类数据使用相同的有效部分,例如key都以{typeId}为前缀
集群伸缩
1 查看redis集群操作命令
redis-cli --cluster提供了很多操作集群的命令,可以通过下面方式查看:
redis-cli --cluster help
2 添加节点
参数说明:
new_host:new_port 新的节点ip和端口
existing_host:existiong_prot 现有redis集群里的ip和端口
可以加的参数:如果不加 添加的节点默认就是master节点
cluster-slave 指定该节点是从节点
clster-master-id 新加的从节点是那个master下的从节点(用节点id指定)
2.1 分盘插槽
3 例子:向集群中添加一个新的master节点,并向其中分配3000插槽
需求:
启动一个新的redis实例,端口为7004
添加7004到之前的集群,并作为一个master节点
给7004节点分配插槽,使得num这个key可以存储到7004实例
3.1 在tmp目录下创建一个7004目录
mkdir 7004
3.2 将tmp目录下的redis配置文件拷贝到7004目录了
cp redis.conf 7004
3.3 将该配置文件中的6379全部替换7004
send -i s/6379/7004/g 7004/redis.conf
3.4 运行
redis-server 7004/redis.conf
3.5 添加新节点
redis-cli --cluster add-node 192.168.150.101:7004 192.168.150.101:7001
3.5.1 查看新集群状态
redis-cli -p 7001 cluster nodes
3.6 给新节点分盘插槽
3.6.1 重新分盘插槽
redis-cli --cluster reshard
3.6.2 指定ip端口(当前链接到集群的ip和端口)
redis-cli --cluster reshard 192.168.150.101:7001
移动多少个插槽?3000个
谁接收插槽 7004
从哪儿拷贝 7001
结束 done->回车
再次确认 yes->回车
查看结果 7004 的插槽就成了 0-2999
故障转移
当集群中有一个master宕机
1 首先是该实例与其它实例失去连接
2 然后是疑似宕机:
3 最后是确定下线,自动提升一个slave为新的master:
数据迁移
利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:
手动的Failover支持三种不同模式:(一般选择默认流程即可)
缺省:默认的流程
force:省略了对offset的一致性校验
takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见
例子:在7002这个slave节点执行手动故障转移,成为master地位
未迁移之前 7002是slave
链接7002
redis-cli -p 7002
迁移
CLUSTER FAILOVER
迁移之后 slave成了master
RedisTemplate访问分片集群
RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致:
1 引入redis的starter依赖
2 配置分片集群地址
3 配置读写分离
与哨兵模式相比,其中只有分片集群的配置方式略有差异,如下:
spring:
redis:
cluster:
nodes: # 指定分片集群的每一个节点信息
- 192.168.150.101:7001
- 192.168.150.101:7002
- 192.168.150.101:7003
- 192.168.150.101:8001
- 192.168.150.101:8002
- 192.168.150.101:8003