• docker搭建redis哨兵集群和分片集群


    搭建哨兵集群

    环境准备拉取镜像

    搭建目标 : 一主而从三哨兵集群

    docker pull redis:6.2.6

    创建文件夹及配置文件

    我这里在/usr/local/docker/redis目录下

    在 redis-master、redis-slave1、redis-slave2 下分别建立data、 redis.conf、 sentinel.conf

    redis配置文件

    在从节点上配置所属于哪个父集群(找爹行动)

    • replicaof 39.106.53.30 6379(redis5.0之后)
    • slaveof 39.106.53.30 6379(5.0之前的命令)
    1. # master redis.conf
    2. save 3600 1
    3. save 300 100
    4. save 60 10000
    5. appendonly no
    6. protected-mode no
    7. port 6379
    8. # redis-slave1 redis.conf
    9. save 3600 1
    10. save 300 100
    11. save 60 10000
    12. appendonly no
    13. bind 0.0.0.0
    14. port 6380
    15. protected-mode no
    16. replicaof 39.106.53.30 6379
    17. # redis-slave2 redis.conf
    18. save 3600 1
    19. save 300 100
    20. save 60 10000
    21. appendonly no
    22. bind 0.0.0.0
    23. port 6381
    24. protected-mode no
    25. replicaof 39.106.53.30 6379

     sentinel配置

    1. # master 配置
    2. port 26379
    3. dir /tmp
    4. sentinel monitor mymaster 39.106.53.30 6379 2
    5. sentinel down-after-milliseconds mymaster 30000
    6. sentinel failover-timeout mymaster 60000
    7. # slave1 配置
    8. port 26380
    9. dir /tmp
    10. sentinel monitor mymaster 39.106.53.30 6379 2
    11. sentinel down-after-milliseconds mymaster 30000
    12. sentinel failover-timeout mymaster 60000
    13. # slave2 配置
    14. port 26381
    15. dir /tmp
    16. sentinel monitor mymaster 39.106.53.30 6379 2
    17. sentinel down-after-milliseconds mymaster 30000
    18. sentinel failover-timeout mymaster 60000

     编写docker-compose.yml

    1. version: '3'
    2. services:
    3. master:
    4. image: redis:6.2.6
    5. container_name: redis-master
    6. command: redis-server /etc/redis/redis.conf
    7. ports:
    8. - 6379:6379
    9. volumes:
    10. - /usr/local/docker/redis/redis-master/data:/data
    11. - /usr/local/docker/redis/redis-master/redis.conf:/etc/redis/redis.conf
    12. slave1:
    13. image: redis:6.2.6
    14. container_name: redis-slave1
    15. volumes:
    16. - /usr/local/docker/redis/redis-slave1/data:/data
    17. - /usr/local/docker/redis/redis-slave1/redis.conf:/etc/redis/redis.conf
    18. command: redis-server /etc/redis/redis.conf
    19. ports:
    20. - 6380:6380
    21. depends_on:
    22. - master
    23. slave2:
    24. image: redis:6.2.6
    25. container_name: redis-slave2
    26. volumes:
    27. - /usr/local/docker/redis/redis-slave2/data:/data
    28. - /usr/local/docker/redis/redis-slave2/redis.conf:/etc/redis/redis.conf
    29. command: redis-server /etc/redis/redis.conf
    30. ports:
    31. - 6381:6381
    32. depends_on:
    33. - master
    34. sentinel1:
    35. image: redis:6.2.6
    36. container_name: redis-sentinel1
    37. command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    38. ports:
    39. - 26379:26379
    40. volumes:
    41. - /usr/local/docker/redis/redis-master/sentinel.conf:/usr/local/etc/redis/sentinel.conf
    42. depends_on:
    43. - master
    44. - slave1
    45. - slave2
    46. sentinel2:
    47. image: redis:6.2.6
    48. container_name: redis-sentinel2
    49. command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    50. ports:
    51. - 26380:26380
    52. volumes:
    53. - /usr/local/docker/redis/redis-slave1/sentinel.conf:/usr/local/etc/redis/sentinel.conf
    54. depends_on:
    55. - master
    56. - slave1
    57. - slave2
    58. sentinel3:
    59. image: redis:6.2.6
    60. container_name: redis-sentinel3
    61. command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    62. ports:
    63. - 26381:26381
    64. volumes:
    65. - /usr/local/docker/redis/redis-slave1/sentinel.conf:/usr/local/etc/redis/sentinel.conf
    66. depends_on:
    67. - master
    68. - slave1
    69. - slave2

     执行docker-compose

    docker-compose up -d

    查看集群信息 

     查看集群信息 info replication

    测试数据同步

    本次搭建的集群,在从节点是只读形式,只有主节点才能够写,在主节点写入 set test test 

    set k v,查看所有从节点信息,在从节点中写,会提示只读副本

    在主节点中写,发现在所有从节点中都存在数据,数据同步成功

    主从集群同步原理

    主从同步第一次同步是全量同步

    master如何判断slave是不是第一次来同步数据:

    Replication ld: 简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid

    ofset:偏移量,随着记录在repl_bak_log中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的ofset如果slave的offset小于master的offset,说明slave数据落后于master,需要更新

    因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据

    但如果slave重启后同步,则执行增量同步

    repl_bak_log大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步

     全量同步流程

    增量同步流程 

    spring boot整合集群并配置读写分离

    引入依赖

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

    配置集群

    由于哨兵模式的节点不固定,所以配置哨兵集群,监听的redis集群由哨兵去找

    1. server:
    2. port: 9000
    3. spring:
    4. redis:
    5. sentinel:
    6. master: mymaster
    7. nodes:
    8. - 39.106.53.30:26379
    9. - 39.106.53.30:26380
    10. - 39.106.53.30:26381

    测试集群同步

    这里的ReadFrom是配置Redis的读取策略:

    • MASTER:从主节点读取.
    • MASTER PREFERRED:优先从master节点读取,master不可用才读取replica
    • REPLICA: 从slave (replica)节点读取
    • REPLICA PREFERRED: 优先从slave (replica)节点读取,所有的slave都不可用才读取master
    1. package com.test.cluster.rediscluster;
    2. import io.lettuce.core.ReadFrom;
    3. import org.springframework.boot.SpringApplication;
    4. import org.springframework.boot.autoconfigure.SpringBootApplication;
    5. import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
    6. import org.springframework.context.annotation.Bean;
    7. @SpringBootApplication
    8. public class RedisClusterApplication {
    9. public static void main(String[] args) {
    10. SpringApplication.run(RedisClusterApplication.class, args);
    11. }
    12. @Bean
    13. public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
    14. return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
    15. }
    16. }

     编写controller

    1. package com.test.cluster.rediscluster.controller;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.data.redis.core.StringRedisTemplate;
    4. import org.springframework.web.bind.annotation.PathVariable;
    5. import org.springframework.web.bind.annotation.RequestMapping;
    6. import org.springframework.web.bind.annotation.RestController;
    7. /**
    8. * @Author sl
    9. */
    10. @RestController
    11. public class TestRedisSentinelController {
    12. @Autowired
    13. private StringRedisTemplate redisTemplate;
    14. @RequestMapping("/get/{key}")
    15. public String getKey(@PathVariable("key") String key){
    16. String s = redisTemplate.opsForValue().get(key);
    17. if(s!= null){
    18. return "获取"+ s + "成功";
    19. }
    20. return "获取"+ key + "失败";
    21. }
    22. @RequestMapping("set/{key}/{value}")
    23. public String setValue(@PathVariable("key")String key,@PathVariable("value") String value){
    24. redisTemplate.opsForValue().set(key,value);
    25. return "set" + key + "success";
    26. }
    27. }

    设置key http://localhost:9000/set/china/yyds ,在80和81中,可以查到china的值

    搭建分片集群

    redis 哨兵模式虽然提供了 redis⾼可⽤、高并发读的解决方案,但是在海量数据应用场景下,仍然存在海量数据存储问题和高并发写的问题。当只有⼀个 Master 对外提供服务时,如果数据量特别⼤,内存占⽤问题严重,数据的高并发写、数据备份和恢复都会⼤⼤降低效率,针对这些问题,redis 推出 Cluster 集群架构,该结构具有如下特点:

    Redis Cluster 采用的去中心化的网络拓扑架构,没有中心节点,所有节点既是数据存储节点,也是控制节点

    引入槽(slot)的概念,通过 CRC+hashslot 算法支持多个主节点(分片),每个主节点分别负责存储一部分数据,这样理论上可以支持无限主节点的水平扩容以便支持海量吞吐量

    在 Cluster 集群里设置了 16384 个哈希槽(hash slot),在 master 节点上写键值对数据时,redis 先对每个键(key),用CRC16 算法对 key 进行运算,然后用 16384 对运算结果取模,余数作为插槽,每个槽在不同的节点下,形成了分片

    内置类似哨兵的高可用机制,能够实现自动故障转移,保证每个主节点的高可用

    创建文件和映射

    创建6379-6384的文件夹,目录为data ,redis.conf

    编写redis.conf

    1. port 6379
    2. daemonize no
    3. cluster-enabled yes
    4. # reids维护
    5. cluster-config-file nodes_6379.conf
    6. tcp-keepalive 300
    7. timeout 0
    8. appendonly yes
    9. logfile "redis_6379.log"
    10. bind 0.0.0.0
    11. cluster-node-timeout 5000
    12. protected-mode no
    13. cluster-announce-ip 39.106.53.30
    14. cluster-announce-bus-port 16379

    编写docker-compose

    1. version: '3'
    2. services:
    3. node1:
    4. image: redis:6.2.6
    5. container_name: redis-node1
    6. restart: always
    7. ports:
    8. - 6379:6379
    9. - 16379:16379
    10. volumes:
    11. - /usr/local/docker/redis/6379/data:/data
    12. - /usr/local/docker/redis/6379/redis.conf:/etc/redis/redis.conf
    13. command:
    14. redis-server /etc/redis/redis.conf
    15. node2:
    16. image: redis:6.2.6
    17. container_name: redis-node2
    18. restart: always
    19. ports:
    20. - 6380:6380
    21. - 16380:16380
    22. volumes:
    23. - /usr/local/docker/redis/6380/data:/data
    24. - /usr/local/docker/redis/6380/redis.conf:/etc/redis/redis.conf
    25. command:
    26. redis-server /etc/redis/redis.conf
    27. node3:
    28. image: redis:6.2.6
    29. container_name: redis-node3
    30. restart: always
    31. ports:
    32. - 6381:6381
    33. - 16381:16381
    34. volumes:
    35. - /usr/local/docker/redis/6381/data:/data
    36. - /usr/local/docker/redis/6381/redis.conf:/etc/redis/redis.conf
    37. command:
    38. redis-server /etc/redis/redis.conf
    39. node4:
    40. image: redis:6.2.6
    41. container_name: redis-node4
    42. restart: always
    43. ports:
    44. - 6382:6382
    45. - 16382:16382
    46. volumes:
    47. - /usr/local/docker/redis/6382/data:/data
    48. - /usr/local/docker/redis/6382/redis.conf:/etc/redis/redis.conf
    49. command:
    50. redis-server /etc/redis/redis.conf
    51. node5:
    52. image: redis:6.2.6
    53. container_name: redis-node5
    54. restart: always
    55. ports:
    56. - 6383:6383
    57. - 16383:16383
    58. volumes:
    59. - /usr/local/docker/redis/6383/data:/data
    60. - /usr/local/docker/redis/6383/redis.conf:/etc/redis/redis.conf
    61. command:
    62. redis-server /etc/redis/redis.conf
    63. node6:
    64. image: redis:6.2.6
    65. container_name: redis-node6
    66. restart: always
    67. ports:
    68. - 6384:6384
    69. - 16384:16384
    70. volumes:
    71. - /usr/local/docker/redis/6384/data:/data
    72. - /usr/local/docker/redis/6384/redis.conf:/etc/redis/redis.conf
    73. command:
    74. redis-server /etc/redis/redis.conf

    执行docker-compose

    docker-compose up -d

    集群启动 

    进入任意节点 docker exec -it redis-node1 /bin/bash

    redis-cli --cluster create 39.106.53.30:6379 39.106.53.30:6380 39.106.53.30:6381 39.106.53.30:6382 39.106.53.30:6383 39.106.53.30:6384 --cluster-replicas 1

    --cluster-replicas 或者 --replicas 1 表示集群中每个master的副本数为1,此时 节点总数/(replicas+1)得到的就是master的数量,因此节点中前n个是master节点 

    查看集群信息 

    连接集群

    以cluster方式连接集群,并set test test 值 ,在其他节点中有相同的值

    spring boot 整合分片集群

    更改配置

    1. server:
    2. port: 9000
    3. # 哨兵集群
    4. #spring:
    5. # redis:
    6. # sentinel:
    7. # master: mymaster
    8. # nodes:
    9. # - 39.106.53.30:26379
    10. # - 39.106.53.30:26380
    11. # - 39.106.53.30:26381
    12. # 分片集群
    13. spring:
    14. redis:
    15. cluster:
    16. nodes:
    17. - 39.106.53.30:6379
    18. - 39.106.53.30:6380
    19. - 39.106.53.30:6381
    20. - 39.106.53.30:6382
    21. - 39.106.53.30:6383
    22. - 39.106.53.30:6384

     测试controller

    1. package com.test.cluster.rediscluster.controller;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.data.redis.core.StringRedisTemplate;
    4. import org.springframework.web.bind.annotation.PathVariable;
    5. import org.springframework.web.bind.annotation.RequestMapping;
    6. import org.springframework.web.bind.annotation.RestController;
    7. /**
    8. * @Author sl
    9. */
    10. @RestController
    11. public class TestRedisClusterController {
    12. @Autowired
    13. private StringRedisTemplate redisTemplate;
    14. @RequestMapping("/get/{key}")
    15. public String getKey(@PathVariable("key") String key){
    16. String s = redisTemplate.opsForValue().get(key);
    17. if(s!= null){
    18. return "获取"+ s + "成功";
    19. }
    20. return "获取"+ key + "失败";
    21. }
    22. @RequestMapping("set/{key}/{value}")
    23. public String setValue(@PathVariable("key")String key,@PathVariable("value") String value){
    24. redisTemplate.opsForValue().set(key,value);
    25. return "set" + key + "success";
    26. }
    27. }

    测试集群

  • 相关阅读:
    OWASP-TOP10漏洞-注入漏洞
    【C语言】——三道基础程序练习
    微信小程序:选择器标签摘要
    判断token失效解决方案
    不买后悔的阿里云服务器租用价格表_优惠活动整理_2024新版
    unity的ui跟随鼠标移动
    如何选择图像标注工具?
    06_JavaScript数组
    《计算机图形学编程(使用OpenGL和C++)》笔记(2)-图形管线和矩阵变换
    Scala核心-编译解释
  • 原文地址:https://blog.csdn.net/m0_65775063/article/details/132742878