ToB企服应用市场:ToB评测及商务社交产业平台

标题: 搭建Redis“主-从-从”模式集群并使用 RedisTemplate 实现读写分离 [打印本页]

作者: 王柳    时间: 2024-10-10 01:26
标题: 搭建Redis“主-从-从”模式集群并使用 RedisTemplate 实现读写分离
一、理论相关

我们知道,Redis具有高可靠性,其含义包括:
Redis主从库模式 - 保证数据副本的同等(读写分离):
采用读写分离的原因:
这时我们就引出主从库同步的原理
1、主从库间如何举行第一次同步?

当我们启动多个 Redis 实例的时候,它们相互之间就可以通过 replicaof(Redis 5.0 之前使用 slaveof)命令形成主库和从库的关系,之后会按照三个阶段完成数据的第一次同步。
  1. replicaof 172.16.19.3 6379
复制代码


2、主从级联模式分担全量复制时的主库压力

一次全量复制中,对于主库需要完成两个耗时操纵:
至此,我们引出:“主 - 从 - 从”模式

3、主从库间网络断了怎么办?

在 Redis 2.8 之前,假如主从库在命令流传时出现了网络闪断,那么,从库就会和主库重新举行一次全量复制,开销非常大。
从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。
4、小结

二、实践

运行环境:假造机操纵系统:centOS7,IP地址:192.168.88.130
已经安装好了 docker 和 docker-compose
采用Redis:7.4.0
至此,我们开始在假造机中搭建Redis“主-从-从”模式的主从库集群
  1. [root@centos ~]# mkdir /root/docker/redis-cluster
  2. [root@centos ~]# cd /root/docker/redis-cluster
  3. [root@centos redis-cluster]# mkdir redis0
  4. [root@centos redis-cluster]# mkdir redis1
  5. [root@centos redis-cluster]# mkdir redis2
  6. [root@centos redis-cluster]# mkdir redis3
  7. [root@centos redis-cluster]# mkdir redis4
复制代码
我们将redis0作为主库
redis1和redis2作为从库I和从库II(slave),redis3和redis4作为从库II的两个从库(主-从-从模式)
  1. [root@centos redis-cluster]# mkdir redis0/data
  2. [root@centos redis-cluster]# vi redis0/redis.conf
复制代码
  1. protected-mode no
  2. bind 0.0.0.0
  3. save 900 1
  4. save 300 10
  5. save 60 10000
  6. rdbcompression yes
  7. dbfilename dump.rdb
  8. dir /data
  9. # 关闭 aof 日志备份
  10. appendonly no
  11. # 自定义密码
  12. requirepass root
  13. # 启动端口
  14. port 6379
  15. # 换成自己的虚拟机的IP
  16. replica-announce-ip 192.168.88.130
复制代码
  1. [root@centos redis-cluster]# mkdir redis1/data
  2. [root@centos redis-cluster]# vi redis1/redis.conf
复制代码
  1. protected-mode no
  2. bind 0.0.0.0
  3. save 900 1
  4. save 300 10
  5. save 60 10000
  6. rdbcompression yes
  7. dbfilename dump.rdb
  8. dir /data
  9. # 关闭 aof 日志备份
  10. appendonly no
  11. # 启动端口
  12. port 6479
  13. # 将当前 redis 作为 redis0 的 slave
  14. # 由于 docker 使用 host 模式,使用的是宿主机的 ip
  15. replicaof 192.168.88.130 6379
  16. # 自定义密码
  17. requirepass root
  18. # 访问 master 节点时需要提供的密码
  19. masterauth root
  20. masteruser redis0
  21. replica-announce-ip 192.168.88.130
复制代码
  1. [root@centos redis-cluster]# mkdir redis2/data
  2. [root@centos redis-cluster]# vi redis2/redis.conf
复制代码
  1. protected-mode no
  2. bind 0.0.0.0
  3. save 900 1
  4. save 300 10
  5. save 60 10000
  6. rdbcompression yes
  7. dbfilename dump.rdb
  8. dir /data
  9. # 关闭 aof 日志备份
  10. appendonly no
  11. # 启动端口
  12. port 6579
  13. # 将当前 redis 作为 redis0 的 slave
  14. # 由于 docker 使用 host 模式,使用的是宿主机的 ip
  15. replicaof 192.168.88.130 6379
  16. # 自定义密码
  17. requirepass root
  18. # 访问 master 节点时需要提供的密码
  19. masterauth root
  20. replica-announce-ip 192.168.88.130
复制代码
  1. [root@centos redis-cluster]# mkdir redis3/data
  2. [root@centos redis-cluster]# vi redis3/redis.conf
复制代码
  1. protected-mode no
  2. bind 0.0.0.0
  3. save 900 1
  4. save 300 10
  5. save 60 10000
  6. rdbcompression yes
  7. dbfilename dump.rdb
  8. dir /data
  9. # 关闭 aof 日志备份
  10. appendonly no
  11. # 启动端口
  12. port 6679
  13. # 将当前 redis 作为 redis2 的 slave
  14. # 由于 docker 使用 host 模式,使用的是宿主机的 ip
  15. replicaof 192.168.88.130 6579
  16. # 自定义密码
  17. requirepass root
  18. # 访问 master 节点时需要提供的密码
  19. masterauth root
  20. replica-announce-ip 192.168.88.130
复制代码
  1. [root@centos redis-cluster]# mkdir redis4/data
  2. [root@centos redis-cluster]# vi redis4/redis.conf
复制代码
  1. protected-mode no
  2. bind 0.0.0.0
  3. save 900 1
  4. save 300 10
  5. save 60 10000
  6. rdbcompression yes
  7. dbfilename dump.rdb
  8. dir /data
  9. # 关闭 aof 日志备份
  10. appendonly no
  11. # 启动端口
  12. port 6779
  13. # 将当前 redis 作为 redis2 的 slave
  14. # 由于 docker 使用 host 模式,使用的是宿主机的 ip
  15. replicaof 192.168.88.130 6579
  16. # 自定义密码
  17. requirepass root
  18. # 访问 master 节点时需要提供的密码
  19. masterauth root
  20. replica-announce-ip 192.168.88.130
复制代码
接下来,我们在目录redis-cluster下新建文件docker-compose.yml:
  1. services:
  2.   redis0:
  3.     image: redis
  4.     container_name: redis0
  5.     restart: always
  6.     privileged: true
  7.     network_mode: "host"
  8.     volumes:
  9.       - /root/docker/redis-cluster/redis0/data:/data
  10.       - /root/docker/redis-cluster/redis0/redis.conf:/etc/redis.conf
  11.     command:
  12.       redis-server /etc/redis.conf
  13.   redis1:
  14.     image: redis
  15.     container_name: redis1
  16.     restart: always
  17.     privileged: true
  18.     network_mode: "host"
  19.     volumes:
  20.       - /root/docker/redis-cluster/redis1/data:/data
  21.       - /root/docker/redis-cluster/redis1/redis.conf:/etc/redis.conf
  22.     command:
  23.       redis-server /etc/redis.conf
  24.     depends_on:
  25.       - redis0
  26.   redis2:
  27.     image: redis
  28.     container_name: redis2
  29.     restart: always
  30.     privileged: true
  31.     network_mode: "host"
  32.     volumes:
  33.       - /root/docker/redis-cluster/redis2/data:/data
  34.       - /root/docker/redis-cluster/redis2/redis.conf:/etc/redis.conf
  35.     command:
  36.       redis-server /etc/redis.conf
  37.     depends_on:
  38.       - redis0
  39.   redis3:
  40.     image: redis
  41.     container_name: redis3
  42.     restart: always
  43.     privileged: true
  44.     network_mode: "host"
  45.     volumes:
  46.       - /root/docker/redis-cluster/redis3/data:/data
  47.       - /root/docker/redis-cluster/redis3/redis.conf:/etc/redis.conf
  48.     command:
  49.       redis-server /etc/redis.conf
  50.     depends_on:
  51.       - redis2
  52.   redis4:
  53.     image: redis
  54.     container_name: redis4
  55.     restart: always
  56.     privileged: true
  57.     network_mode: "host"
  58.     volumes:
  59.       - /root/docker/redis-cluster/redis4/data:/data
  60.       - /root/docker/redis-cluster/redis4/redis.conf:/etc/redis.conf
  61.     command:
  62.       redis-server /etc/redis.conf
  63.     depends_on:
  64.       - redis2
复制代码
  1. [root@centos redis-cluster]# vi docker-compose.yml
  2. [root@centos redis-cluster]# docker-compose up -d
复制代码
摆设完成后,我们使用RDM连接摆设的所有redis:
测试是否连接成功:
redis0:
redis1:
redis2:
redis3、redis4同理。
测试五个主从库读写操纵:
redis0:(可读可写)
redis1、redis2:(可读不可写)
并且我们发现,redis1和redis2举行了主从库同步操纵,纵然我们没有在redis1和redis2中写入name:Monica,但它们和redis0创建连接后,主库会将数据同步给从库
redis3、redis4作为redis2的从库,同理,包含redis2的所有数据。
从RDM中我们也可以直观地看出,我们只对主库举行了一次写操纵,但其连接的所有从库(包括从库的从库)都包含了这个数据:
通过以上验证表明:redis 的“主-从-从”模式集群已经搭建成功。
三、RedisTemplate 操纵 Redis 集群实现读写分离

1、新建项目

我们新建一个SpringBoot项目,项目结构如下:
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-data-redis</artifactId>
  4. </dependency>
复制代码
  1. spring:
  2.     data:
  3.         redis:
  4.             # 这里只需配置主节点的信息即可
  5.             # RedisTemplate可以从主节点信息中获取从节点信息
  6.             host: 192.168.88.130
  7.             port: 6379
  8.             password: root
  9.             jedis:
  10.                 pool:
  11.                     # 最大连接数
  12.                     max-active: 10
  13.                     # 最大空闲连接数
  14.                     max-idle: 5
  15.                     # 最小空闲
  16.                     min-idle: 1
  17.                     # 连接超时时间(毫秒)
  18.                     max-wait: 8000
复制代码
  1. package com.chen.redisdemo.redisConfig;
  2. import io.lettuce.core.ReadFrom;
  3. import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.data.redis.connection.RedisConnectionFactory;
  7. import org.springframework.data.redis.core.RedisTemplate;
  8. import org.springframework.data.redis.serializer.StringRedisSerializer;
  9. /**
  10. * @version 1.0
  11. * @Author feiye
  12. * @Date 2024-10-06 12:15
  13. * @className RedisConfig
  14. * @since 1.0
  15. */
  16. @Configuration
  17. public class RedisConfig {
  18.     //你可以将读取策略,设置为 ReadFrom.REPLICA 表示只从 slave 节点读取数据
  19.     //然后你把 slave 节点全部停掉,然后看看是否能够读取成功
  20.     @Bean
  21.     public LettuceClientConfigurationBuilderCustomizer redisClientConfig() {
  22.         //配置 redisTemplate 优先从 slave 节点读取数据,如果 slave 都宕机了,则从 master 读取
  23.         return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
  24.         //配置 redisTemplate 优先从 slave 节点读取数据,如果 slave 都宕机了,则抛出异常
  25.         //return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA);
  26.     }
  27.     @Bean
  28.     public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
  29.         RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
  30.         //默认的Key序列化器为:JdkSerializationRedisSerializer
  31.         redisTemplate.setKeySerializer(new StringRedisSerializer());
  32.         redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  33.         redisTemplate.setConnectionFactory(connectionFactory);
  34.         redisTemplate.setEnableTransactionSupport(true);
  35.         return redisTemplate;
  36.     }
  37. }
复制代码
  1. package com.chen.redisdemo;
  2. import org.junit.jupiter.api.Test;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. import org.springframework.data.redis.core.RedisTemplate;
  6. @SpringBootTest
  7. class RedisDemoApplicationTests {
  8.     @Autowired
  9.     private RedisTemplate redisTemplate;
  10.     @Test
  11.     void writeTest() {
  12.         redisTemplate.opsForValue().set("name", "Ross");
  13.     }
  14.     @Test
  15.     void getTest() {
  16.         Object name = redisTemplate.opsForValue().get("name");
  17.         if (name != null) {
  18.             System.out.println(name.toString());
  19.         }
  20.     }
  21. }
复制代码
2、如何证明 RedisTemplate 是从 Slave 节点中获取数据的?

  1. @Bean
  2. public LettuceClientConfigurationBuilderCustomizer redisClientConfig() {
  3.     //配置 redisTemplate 优先从 slave 节点读取数据,如果 slave 都宕机了,则抛出异常
  4.     return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA);
  5. }
复制代码
  1. [root@centos redis-cluster]# docker-compose stop redis3
  2. [+] Stopping 1/1
  3. ✔ Container redis3  Stopped                                                                                                                                                                                 0.3s
  4. [root@centos redis-cluster]# docker-compose stop redis4
  5. [+] Stopping 1/1
  6. ✔ Container redis4  Stopped                                                                                                                                                                                 0.2s
  7. [root@centos redis-cluster]# docker-compose stop redis2
  8. [+] Stopping 1/1
  9. ✔ Container redis2  Stopped                                                                                                                                                                                 0.2s
  10. [root@centos redis-cluster]# docker-compose stop redis1
  11. [+] Stopping 1/0
  12. ✔ Container redis1  Stopped
复制代码
然后我们运行getTest()测试类,发现报错:
我们发现,假如主节点和从节点全部宕机,只要启动此中一个从节点,主节点就会同时启动
此时已经可以读取了。说明 RedisTemplate 就是从 Slave 节点中读取数据的。
测试完毕。
个人题目记载:

在举行摆设后发现主从库连接失败,详情如下:
redis0:
redis1:
通过docker logs redis0查看日志,排查错误后发现是端口6379被占用。因为在之前我摆设过单机redis,使用了端口6379,但没有将其kill,导致端口被占用
本人采用最粗暴的方法就是直接把容器rm了^^
参考博文:
Redis 主从集群搭建并使用 RedisTemplate 实现读写分离
参考书籍:
《Redis核心技术与实战》

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4