• redis集群


    redis单节点存在的问题

    reids持久化

    1.RDB持久化

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

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

    • 执行save命令

    • 执行bgsave命令

    • Redis停机时

    • 触发RDB条件时

    RDB的设置和使用

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

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

    效果图为下: 

     

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

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

    1. #异步完成RDB操作
    2. bgsave

    效果图为下:

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

     RDB触发条件设置

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

    效果图为下:
     

     RDB的其他配置

    1. #快照压缩,占用CPU,减少磁盘开销
    2. rdbcompression yes
    3. #设置RDB的文件,也就是生成快照的名字和使用快照恢复数据时对应的快照名
    4. dbfilename dump.rdb

    效果图为下: 

     

    RDB的执行原理

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

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

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

     RDB的缺点

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

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

     2.AOF持久化

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

    AOF的设置和使用 

    AOF的开启和文件名设置 

    1. #开启AOF
    2. appendonly yes
    3. #设置AOF文件名
    4. appendfilename "appendonly.aof"

    效果图为下: 

    AOF的模式设置

    1. #总是执行,也就是在每次执行指令时就进行AOF
    2. appendfsync always
    3. #每过一秒执行一次AOF(默认使用策略)
    4. appendfsync everysec
    5. #不进行AOF,执行AOF由系统决定
    6. appendfsync no

    对应效果图为下: 

     三种策略对比

    AOF文件重写(文件压缩)

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

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

    效果图为下: 

    RDB和AOF对比

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

     docker下载redis镜像

    docker pull redis

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

    1. #集群主节点1data文件和conf文件映射
    2. mkdir -p /mydata/redis/cluster/node1/data
    3. mkdir -p /mydata/redis/cluster/node1/conf
    4. touch /mydata/redis/cluster/node1/conf/redis.conf
    5. #集群主节点2data文件和conf文件映射
    6. mkdir -p /mydata/redis/cluster/node2/data
    7. mkdir -p /mydata/redis/cluster/node2/conf
    8. touch /mydata/redis/cluster/node2/conf/redis.conf
    9. #集群主节点3data文件和conf文件映射
    10. mkdir -p /mydata/redis/cluster/node3/data
    11. mkdir -p /mydata/redis/cluster/node3/conf
    12. touch /mydata/redis/cluster/node3/conf/redis.conf
    13. #集群主节点4data文件和conf文件映射
    14. mkdir -p /mydata/redis/cluster/node4/data
    15. mkdir -p /mydata/redis/cluster/node4/conf
    16. touch /mydata/redis/cluster/node4/conf/redis.conf
    17. #集群主节点5data文件和conf文件映射
    18. mkdir -p /mydata/redis/cluster/node5/data
    19. mkdir -p /mydata/redis/cluster/node5/conf
    20. touch /mydata/redis/cluster/node5/conf/redis.conf
    21. #集群主节点6data文件和conf文件映射
    22. mkdir -p /mydata/redis/cluster/node6/data
    23. mkdir -p /mydata/redis/cluster/node6/conf
    24. touch /mydata/redis/cluster/node6/conf/redis.conf

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

    1. #redis节点1容器
    2. docker create --name redis-node1 -v /mydata/redis/cluster/node1/data:/data \
    3. -v /mydata/redis/cluster/node1/conf/redis.conf:/etc/redis/redis.conf \
    4. -p 16379:6379 redis --cluster-enabled yes \
    5. --cluster-config-file redis-node1.conf
    6. #redis节点2容器
    7. docker create --name redis-node2 -v /mydata/redis/cluster/node2/data:/data \
    8. -v /mydata/redis/cluster/node2/conf/redis.conf:/etc/redis/redis.conf \
    9. -p 26379:6379 redis --cluster-enabled yes \
    10. --cluster-config-file redis-node2.conf
    11. #redis节点3容器
    12. docker create --name redis-node3 -v /mydata/redis/cluster/node3/data:/data \
    13. -v /mydata/redis/cluster/node3/conf/redis.conf:/etc/redis/redis.conf \
    14. -p 36379:6379 redis --cluster-enabled yes \
    15. --cluster-config-file redis-node3.conf
    16. #redis节点4容器
    17. docker create --name redis-node4 -v /mydata/redis/cluster/node4/data:/data \
    18. -v /mydata/redis/cluster/node4/conf/redis.conf:/etc/redis/redis.conf \
    19. -p 46379:6379 redis --cluster-enabled yes \
    20. --cluster-config-file redis-node4.conf
    21. #redis节点5容器
    22. docker create --name redis-node5 -v /mydata/redis/cluster/node5/data:/data \
    23. -v /mydata/redis/cluster/node5/conf/redis.conf:/etc/redis/redis.conf \
    24. -p 56379:6379 redis --cluster-enabled yes \
    25. --cluster-config-file redis-node5.conf
    26. #redis节点6容器
    27. docker create --name redis-node6 -v /mydata/redis/cluster/node6/data:/data \
    28. -v /mydata/redis/cluster/node6/conf/redis.conf:/etc/redis/redis.conf \
    29. -p 60000:6379 redis --cluster-enabled yes \
    30. --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地址。

    1. #查看redis节点1的信息
    2. docker inspect redis-node1
    3. #查看redis节点2的信息
    4. docker inspect redis-node2
    5. #查看redis节点3的信息
    6. docker inspect redis-node3
    7. #查看redis节点4的信息
    8. docker inspect redis-node4
    9. #查看redis节点5的信息
    10. docker inspect redis-node5
    11. #查看redis节点6的信息
    12. 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节点中查看集群信息

    1. #进入容器
    2. docker exec -it "id" /bin/bash
    3. #进入redis服务端
    4. redis-cli
    5. #查看集群情况
    6. 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,保证外网也可以访问该节点)

     导入依赖

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-data-redis</artifactId>
    4. </dependency>

    修改application.yml文件的配置

    1. spring:
    2. redis:
    3. cluster:
    4. nodes:
    5. - 132.9.214.176:16379
    6. - 132.9.214.176:26379
    7. - 132.9.214.176:36379
    8. - 132.9.214.176:46379
    9. - 132.9.214.176:56379
    10. - 132.9.214.176:60000

    配置读写分离配置

    1. import io.lettuce.core.ReadFrom;
    2. import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
    3. import org.springframework.context.annotation.Bean;
    4. import org.springframework.context.annotation.Configuration;
    5. @Configuration
    6. public class RedisConfiguration {
    7. //配置读写分离
    8. @Bean
    9. public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
    10. return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
    11. }
    12. }

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

    • MASTER:从主节点读取

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

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

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

    测试

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

     

  • 相关阅读:
    数据分割处理示例
    绩效考核管理项目|记录1
    原生小程序自定义vantUI中van-collapse手风琴组件的标题
    【MyBatis-Plus】简介 | 入门案例
    Containerd shim 原理深入解读
    OpenAI放出的ChatGPT 4的多模态语音和图像更新
    互联网相关概念——RFC
    java---图的BFS广度优先遍历---拓扑序列(每日一道算法2022.8.25)
    ubuntu挂载数据盘,第一次挺顺利
    和鲸科技创始人范向伟受邀出席“凌云出海,来中东吧”2023华为云上海路演活动
  • 原文地址:https://blog.csdn.net/Ostkakah/article/details/132763232