redis集群

redis单节点存在的问题

reids持久化

1.RDB持久化

通过对数据做快照的方式来实现持久化,将内存中的数据存储到磁盘中,在数据需要恢复的时候通过快照进行恢复。

RDB持久化在四种情况下会执行:

  • 执行save命令

  • 执行bgsave命令

  • Redis停机时

  • 触发RDB条件时

RDB的设置和使用

在redis-cli中使用RDB(在主线程中执行)

#产生对应的RDB文件快照
save

效果图为下: 

 

 在执行save操作时会堵塞当前的主线程,会阻塞redis当前的其他操作。

在redis-cli中使用RDB(在子线程中执行)

#异步完成RDB操作
bgsave

效果图为下:

设置RDB配置(redis.conf中设置)

 RDB触发条件设置

#在10秒内有100key对应的值发生改变时进行RDB
# save "间隔" “key的修改次数”
save 300 10

效果图为下:
 

 RDB的其他配置

#快照压缩,占用CPU,减少磁盘开销

rdbcompression yes

#设置RDB的文件,也就是生成快照的名字和使用快照恢复数据时对应的快照名
dbfilename dump.rdb 

效果图为下: 

 

RDB的执行原理

 redis的操作是单线程的,主线程通过页表来映射在物理内存中的对应内存块,在执行RDB的子线程中通过相同的页表来读取对应映射的内存块,从而生成对应的RDB快照。

在子线程执行读取操作时,主线程可能会同时执行增删改操作,这会导致脏读的情况,为了防止这种情况,真正的物理内存块设置了只读的权限。

在主线程中为了能够正常的进行增删改操作,通过复制对应的内存块中的数据,在该数据副本中进行增删改的操作,将页表中的关系映射到新的数据副本上。子进程中的页表不会马上更新,所以子进程的操作不会受到影响。

 RDB的缺点

  • RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险。

  • fork子进程、压缩、写出RDB文件都比较耗时。

 2.AOF持久化

AOF全称为Append Only File(追加文件),通过创建AOF文件将在该数据库中执行的所有指令都记录到AOF文件中,通过AOF文件对数据进行恢复。

AOF的设置和使用 

AOF的开启和文件名设置 

#开启AOF
appendonly yes

#设置AOF文件名
appendfilename "appendonly.aof"

效果图为下: 

AOF的模式设置

#总是执行,也就是在每次执行指令时就进行AOF
appendfsync always

#每过一秒执行一次AOF(默认使用策略)
appendfsync everysec

#不进行AOF,执行AOF由系统决定
appendfsync no

对应效果图为下: 

 三种策略对比

AOF文件重写(文件压缩)

在redis.conf中设置AOF重写触发条件

# AOF文件比上次文件 增长超过多少百分比则触发重写(比上次增加100触发重写)
auto-aof-rewrite-percentage 100
# AOF文件体积最小多大以上才触发重写 (体积大于64mb触发重写)
auto-aof-rewrite-min-size 64mb 

效果图为下: 

RDB和AOF对比

redis主从(集群最少三个节点)

 docker下载redis镜像

docker pull redis

在服务器上创建对应的目录用于给redis的配置文件和持久化文件挂载。

#集群主节点1的data文件和conf文件映射
mkdir -p /mydata/redis/cluster/node1/data 
mkdir -p /mydata/redis/cluster/node1/conf
touch /mydata/redis/cluster/node1/conf/redis.conf

#集群主节点2的data文件和conf文件映射
mkdir -p /mydata/redis/cluster/node2/data 
mkdir -p /mydata/redis/cluster/node2/conf
touch /mydata/redis/cluster/node2/conf/redis.conf

#集群主节点3的data文件和conf文件映射
mkdir -p /mydata/redis/cluster/node3/data 
mkdir -p /mydata/redis/cluster/node3/conf
touch /mydata/redis/cluster/node3/conf/redis.conf

#集群主节点4的data文件和conf文件映射
mkdir -p /mydata/redis/cluster/node4/data 
mkdir -p /mydata/redis/cluster/node4/conf
touch /mydata/redis/cluster/node4/conf/redis.conf

#集群主节点5的data文件和conf文件映射
mkdir -p /mydata/redis/cluster/node5/data 
mkdir -p /mydata/redis/cluster/node5/conf
touch /mydata/redis/cluster/node5/conf/redis.conf

#集群主节点6的data文件和conf文件映射
mkdir -p /mydata/redis/cluster/node6/data 
mkdir -p /mydata/redis/cluster/node6/conf
touch /mydata/redis/cluster/node6/conf/redis.conf

创建redis节点1的容器和redis节点2的容器(端口记得开放)

#redis节点1容器
docker create --name redis-node1 -v /mydata/redis/cluster/node1/data:/data  \
-v /mydata/redis/cluster/node1/conf/redis.conf:/etc/redis/redis.conf  \
-p 16379:6379 redis --cluster-enabled yes  \
--cluster-config-file redis-node1.conf

#redis节点2容器
docker create --name redis-node2 -v /mydata/redis/cluster/node2/data:/data  \
-v /mydata/redis/cluster/node2/conf/redis.conf:/etc/redis/redis.conf  \
-p 26379:6379 redis --cluster-enabled yes  \
--cluster-config-file redis-node2.conf

#redis节点3容器
docker create --name redis-node3 -v /mydata/redis/cluster/node3/data:/data  \
-v /mydata/redis/cluster/node3/conf/redis.conf:/etc/redis/redis.conf  \
-p 36379:6379 redis --cluster-enabled yes  \
--cluster-config-file redis-node3.conf

#redis节点4容器
docker create --name redis-node4 -v /mydata/redis/cluster/node4/data:/data  \
-v /mydata/redis/cluster/node4/conf/redis.conf:/etc/redis/redis.conf  \
-p 46379:6379 redis --cluster-enabled yes  \
--cluster-config-file redis-node4.conf

#redis节点5容器
docker create --name redis-node5 -v /mydata/redis/cluster/node5/data:/data  \
-v /mydata/redis/cluster/node5/conf/redis.conf:/etc/redis/redis.conf  \
-p 56379:6379 redis --cluster-enabled yes  \
--cluster-config-file redis-node5.conf

#redis节点6容器
docker create --name redis-node6 -v /mydata/redis/cluster/node6/data:/data  \
-v /mydata/redis/cluster/node6/conf/redis.conf:/etc/redis/redis.conf  \
-p 60000:6379 redis --cluster-enabled yes  \
--cluster-config-file redis-node6.conf

启动两个容器

docker start redis-node1 redis-node2 redis-node3 redis-node4 redis-node5 redis-node6

查看容器运行状态

docker ps

效果图为下:

设置集群关系(主从关系,最少六个节点,以上述方式创建六个节点)

 分别查看redis-node1至redis-node6的IP地址。

#查看redis节点1的信息
docker inspect redis-node1

#查看redis节点2的信息
docker inspect redis-node2

#查看redis节点3的信息
docker inspect redis-node3

#查看redis节点4的信息
docker inspect redis-node4

#查看redis节点5的信息
docker inspect redis-node5


#查看redis节点6的信息
docker inspect redis-node6

 查看的效果图为下:

redis-node1

redis-node2

redis-node3

redis-node4~6都是一样的效果。 

创建集群

redis-cli --cluster create 172.17.0.3:6379 172.17.0.4:6379 172.17.0.5:6379 172.17.0.6:6379 172.17.0.7:6379 172.17.0.8:6379 --cluster-replicas 1

 效果图为下:

此时三个节点是主节点,三个是从节点。

 进入某个redis节点中查看集群信息

#进入容器
docker exec -it "id" /bin/bash

#进入redis服务端
redis-cli

#查看集群情况
cluster nodes

效果图为下:

设置主从关系就是通过  --cluster-replicas 1来控制,如果为1,也就是主节点和从节点的个数为1:1。

主从数据同步原理

主从第一次建立连接时,会执行全量同步,将master节点的所有数据都拷贝给slave节点。

  • Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid(用于判断数据是否为第一次同步)

  • offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。(判断上次数据同步到的位置)

 master判断一个节点是否是第一次同步的依据,就是看replid是否一致

在第二阶段使用的快照的数据同步,也就是RDB。 

 增量同步

此时数据无需完全同步,只需要从偏移量的位置向后同步到终点即可。

repl_backlog中存放数据执行的指令,在数据同步时从当前的偏移量开始的指令用于数据同步。

(有点类似AOF) 

repl_backlog原理

 这就要说到全量同步时的repl_baklog文件了。

这个文件是一个固定大小的数组,只不过数组是环形,也就是说角标到达数组末尾后,会再次从0开始读写,这样数组头部的数据就会被覆盖。(是个闭环)

epl_baklog中会记录主节点redis中数据存储到的偏移量,也会记录从节点在epl_baklog中数据同步到的偏移量,只要二者偏移量相同就说明当前的数据已经是同步的了,如果偏移量之间还有差距说明当前数据还尚未同步。

特殊情况:从节点宕机后数据没有即使同步,主节点的偏移量越过从节点的偏移量,导致部分指令被覆盖,最终数据发生丢失。

解决方案:进行全量同步。

redis哨兵

提供哨兵的监控来实现主从的切换,从而实现故障修复。 哨兵模式是Redis的高可用方式,哨兵节点是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。

哨兵模式的作用
1.监控: sentinel会不断的检查master和salve的运行状态的。

2.自动故障修复:sentinel会在一个master失效时将一个slave作为新的master,而在原本的master恢复后,此master就会成为slave。

3.通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端。

哨兵模式的原理

监控原理

sentinel会基于心跳监测机制,每个1秒向各个实例发送ping指令,判断各个实例的运行状态。

主观下线:当有某个sentinel发现某个实例没有在规定的时间内返回存活回应,则就会认为其下线了,这个就是主观下线。

客观下线: 当超过一定数量的sentinel发现某个实例未在规定的时间内返回存活回应,都认为其主观下线了,则就认为其为客观下线。(这里的一定数量要超过sentinel个数的二分之一

自动故障修复

当发现某个master宕机了,sentinel就会选择一个slave作为新的master。

选择slave的步骤为下(在判断的依据相同时就会进入下一步):

1.判断slave和master断开的时长,如果超过一定的时间(down-after-milliseconds * 10) 则会将此slave排除。

2.判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举。(可以理解成权重)

3.判断slave在repl_backlog中的偏移量的大小,偏移量越大就说明更新的数据越新。

4.判断slave运行id的大小,id越小,执行的优先级越高。

 自动故障修复的设置性master的步骤

1.sentinel给该slave发送指令:slaveof no one ,将slave设置为master。

2.sentinel向其他slave通知这个新的master,其他的slave都执行指令:slaveof "新masterIP" "新master的端口"

3.在原来的master恢复以后,将其设置为slave。

redis分片集群

  在做redis主从时,我们可以看到每个master都被分配了slots,这slots就master对应插槽。

自动故障转移:虽然在分片集群中没有sentinel,但在master宕机时,其会自动将slave设置为新的master,在原来的master恢复后,它会做为新的slave。

手动故障转移:

  手动故障转移的步骤为下:

1.slave节点告诉master节点拒绝如何客户端的请求.

2.master返回当前的数据offset偏移量给slave,用于更新slave的蕞新数据。

3.开始进行故障转移。

4.slave标记自己为master,并将此消息广播给其他的节点。

5.原来的master做为新的slave

RedisTemplate访问分片集群(需要修改redsi.conf,保证外网也可以访问该节点)

 导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

修改application.yml文件的配置

spring:
  redis:
    cluster:
      nodes:
        - 132.9.214.176:16379
        - 132.9.214.176:26379
        - 132.9.214.176:36379
        - 132.9.214.176:46379
        - 132.9.214.176:56379
        - 132.9.214.176:60000

配置读写分离配置

import io.lettuce.core.ReadFrom;
import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedisConfiguration {
    //配置读写分离
    @Bean
    public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
        return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
    }
}

这个bean中配置的就是读写策略,包括四种:

  • MASTER:从主节点读取

  • MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica

  • REPLICA:从slave(replica)节点读取

  • REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master

测试

由于节点未开放外网访问权限,所以这里连接超时,我们只需要注释每个节点的redis.conf中 bind 127.0.0.1 即可,最终完成测试。

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值