首页 > 数据库 >Redis 主从集群搭建并使用 RedisTemplate 实现读写分离

Redis 主从集群搭建并使用 RedisTemplate 实现读写分离

时间:2023-12-19 23:23:42浏览次数:39  
标签:ip redis redis1 节点 Redis 主从 RedisTemplate

单机版的 Redis 能够承载并发访问的能力有限,对于绝大多数的系统而言,都是读多写少,系统之所以宕机,一般都是因为并发读操作太高导致的宕机,因此搭建 Redis 主从集群,实现读写分离,是一种有效的提高并发访问能力的方案。

本篇博客介绍在一台虚拟机上,使用 docker-compose 模拟搭建一个【一主两从】的 Redis 集群,然后搭建一个 SpringBoot 工程,使用 RedisTemplate 连接 Redis 主从集群,实现读写分离功能,并且在博客的最后提供源代码下载。


一、集群搭建

在上篇博客中,我们已经使用 docker-compose 搭建了单机版的 Redis,本篇博客仍然使用这台虚拟机环境。

我的虚拟机操作系统是 CentOS7(ip 地址是 192.168.136.128),已经安装好了 docker 和 docker-compose

首先我们先创建好目录 /app/redis-cluster 并在其下面创建 3 个子文件夹 redis1、redis2、redis3

在每个 redis 目录下,创建一个配置文件 redis.conf,以及创建一个 data 文件夹用来存储备份数据

image

我们使用 redis1 作为主节点(master),redis2 和 redis3 作为从节点(slave),首先我们先编辑好配置文件

先列出 redis1 的 redis.conf 配置文件,作为主节点,配置文件比较简单

protected-mode no

bind 0.0.0.0

save 900 1
save 300 10
save 60 10000

rdbcompression yes

dbfilename dump.rdb

dir /data

# 关闭 aof 日志备份
appendonly no

# 自定义密码
requirepass root

# 启动端口
port 6379

# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
replica-announce-ip 192.168.136.128

然后看一下 redis2 的 redis.conf 配置文件内容,最重要的 2 项配置如下:

  • slaveof [主节点ip] [主节点端口] ,该配置主要是让当前节点作为从节点,配置具体的主节点的地址和端口
  • masterauth [主节点的访问密码] ,该配置主要是在主节点设置密码的情况下,能够让从节点通过密码访问主节点
protected-mode no

bind 0.0.0.0

save 900 1
save 300 10
save 60 10000

rdbcompression yes

dbfilename dump.rdb

dir /data

# 关闭 aof 日志备份
appendonly no

# 启动端口
port 6479

# 将当前 redis 作为 redis1 的 slave
# 由于 docker 使用 host 模式,使用的是宿主机的 ip
slaveof 192.168.136.128 6379

# 自定义密码
requirepass root

# 访问 master 节点时需要提供的密码
masterauth root

# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
replica-announce-ip 192.168.136.128

redis3 的配置文件 redis.conf 如下所示,基本跟 redis2 的配置文件一样,唯一不同的就是启动端口:

protected-mode no

bind 0.0.0.0

save 900 1
save 300 10
save 60 10000

rdbcompression yes

dbfilename dump.rdb

dir /data

# 关闭 aof 日志备份
appendonly no

# 启动端口
port 6579

# 将当前 redis 作为 redis1 的 slave
# 由于 docker 使用 host 模式,使用的是宿主机的 ip
slaveof 192.168.136.128 6379

# 自定义密码
requirepass root

# 访问 master 节点时需要提供的密码
masterauth root

# 虚拟机会有多个 ip,这里指定具体一个 ip 地址
replica-announce-ip 192.168.136.128

最后总结一下 3 个 redis 的配置文件特点:

  • 三个 redis 节点,如果要是设置访问密码的话,最好设置相同的密码,比如本篇博客设置的密码都是 root
  • 由于在同一台虚拟机上部署,为了方便 docker 外部的 java 代码访问,因此后面将使用 docker 的 host 部署模式,也就是三个节点的 redis 将使用虚拟机的 ip 和端口,因此这三个 redis 的配置文件,必须配置不同的服务端口。本篇博客中 redis1、redis2、redis3 分别使用 6379、6479、6579 端口。
  • 三个 redis 节点,都是用默认的 rdb 数据备份存储方式,关闭了 aof 的日志备份方式,可以提高性能
  • 如果主节点设置的访问密码,从节点需要在配置文件使用 masterauth [主节点的访问密码] 配置,确保能够访问主节点
  • 通过在从节点的配置文件中使用 slaveof [主节点ip] [主节点端口] 配置,指定该从节点的主节点
  • 使用 docker 的 host 模式后,三个节点使用的是虚拟机的 ip ,由于虚拟机可能有多个网卡,会存在多个 ip 地址,因为必须让 3 个节点绑定在同一个网卡上,也就是绑定同一个 ip 地址,使用 replica-announce-ip [ip地址] 进行配置即可

最后我们在 /app/redis-cluster 目录下创建一个 docker-compose.yml 文件,填写内容如下:

version: "3.5"
services:
  redis1:
    image: redis
    container_name: redis1
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /app/redis-cluster/redis1/data:/data
      - /app/redis-cluster/redis1/redis.conf:/etc/redis.conf
    command:
      redis-server /etc/redis.conf

  redis2:
    image: redis
    container_name: redis2
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /app/redis-cluster/redis2/data:/data
      - /app/redis-cluster/redis2/redis.conf:/etc/redis.conf
    command:
      redis-server /etc/redis.conf
    depends_on:
      - redis1

  redis3:
    image: redis
    container_name: redis3
    restart: always
    privileged: true
    network_mode: "host"
    volumes:
      - /app/redis-cluster/redis3/data:/data
      - /app/redis-cluster/redis3/redis.conf:/etc/redis.conf
    command:
      redis-server /etc/redis.conf
    depends_on:
      - redis1

然后在 docker-compose.yml 所在目录运行 docker-compose up -d 命令启动 3 个 redis 服务即可。

启动成功后,可以使用 docker-compose psdocker ps 查看服务的启动状态:

image

使用 RDM 客户端工具,分别连接 redis1、redis2、redis3

它们的 ip 地址都是 192.168.136.128,密码都是 root,连接端口分别是 6379、6479、6579

连接上任何一个 redis 节点,都可以运行 info replication 命令查看集群节点状况,比如我们连接主节点 redis1

image

然后我们对 3 个 redis 节点进行操作,发现 redis1 主节点可读可写,而 redis2 和 redis3 这俩从节点,只能读,不能写。

redis1 主节点上写入的数据,很快就同步到了 redis2 和 redis3 这俩从节点上。

image

OK,通过以上验证表明:redis 的一主量从集群,已经搭建成功。


二、RedisTemplate 操作 Redis 集群实现读写分离

新建一个 SpringBoot 工程,名称为 springboot_redis_cluster1,结构如下图所示:

image

代码非常简单,这里就直接把细节列出来,首先看一下 application.yml 配置文件:

spring:
  redis:
    # 这里只配置主节点的连接信息即可,
    # 因为 RedisTemplate 可以从主节点中获取从节点的信息
    host: 192.168.136.128
    port: 6379
    password: root
    jedis:
      pool:
        # 最大连接数
        max-active: 10
        # 最大空闲连接数
        max-idle: 5
        # 最小空闲
        min-idle: 1
        # 连接超时时间(毫秒)
        max-wait: 3000

这里只需要配置 redis1 主节点的连接信息即可,因为 RedisTemplate 可以从主节点中获取从节点的信息。

然后我们需要对 RedisTemplate 进行一下配置:

package com.jobs.config;

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;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    //你可以将读取策略,设置为 ReadFrom.REPLICA 表示只从 slave 节点读取数据
    //然后你把 slave 节点全部停掉,然后看看是否能够读取成功
    @Bean
    public LettuceClientConfigurationBuilderCustomizer redisClientConfig() {
        //配置 redisTemplate 优先从 slave 节点读取数据,如果 slave 都宕机了,则从 master 读取
        return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);

        //配置 redisTemplate 优先从 slave 节点读取数据,如果 slave 都宕机了,则抛出异常
        //return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        //默认的Key序列化器为:JdkSerializationRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }
}

由于 RedisTemplate 底层使用的是 Lettuce ,因此这里配置客户端读取方式:ReadFrom.REPLICA_PREFERRED 表示优先从 slave 节点中读取数据,如果 slave 节点都挂掉了,或者响应超时,则从主节点读取数据。

最后就是编写一个测试类 RedisClusterTest ,测试对 Redis 集群的读写操作,如下所示:

package com.jobs;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
public class RedisClusterTest {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void writeTest() {
        redisTemplate.opsForValue().set("name", "jobs");
    }

    @Test
    void getTest() {
        Object name = redisTemplate.opsForValue().get("name");
        if (name != null) {
            System.out.println(name.toString());
        }
    }
}

运行以上 2 个测试方法,即可从 Redis 集群中读写数据,代码及其简单,跟访问单机版的 Redis 一模一样。


三、如何证明 RedisTemplate 是从 Slave 节点中获取数据的

写入数据是操作 redis1 这个 master 节点的,因为上面 Redis 集群搭建好后,我们已经验证过 Slave 节点只读不可写。

首先我们先运行一下 writeTest 方法,向 Redis 集群中写入数据,因为测试读取的时候,需要用到。

运行以上的 getTest 测试方法,通过控制台的日志,并不能看出 RedisTemplate 是从 Slave 节点中读取数据的。

为了能够证明 RedisTemplate 是从 Slave 节点中读取数据的,需要进行以下操作:

首先我们修改一下 RedisConfig 类中的配置,让 RedisTemplate 只从 Slave 节点读取数据,不从 master 节点读取数据。

@Bean
public LettuceClientConfigurationBuilderCustomizer redisClientConfig() {
    //配置 redisTemplate 优先从 slave 节点读取数据,如果 slave 都宕机了,则抛出异常
    return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA);
}

然后我们在 Linux 虚拟机上,执行以下命令,停掉 redis2 和 redis3 这两个 Slave 节点服务:

docker-compose stop redis2
docker-compose stop redis3

此时再执行测试类 RedisClusterTest 下的 getTest 方法,你会发现报错,原因是无法找到一个节点来读取数据。

image

此时你只要把 redis2、redis3 任意一个 Slave 节点启动起来,或者两个 Slave 节点都启动起来,再运行 getTest 方法,就能够获取数据成功。

docker-compose start redis2
docker-compose start redis3

image

通过以上操作,就足够可以证明,RedisTemplate 就是从 Slave 节点中读取数据的。

RedisTemplate 对 Redis 集群的访问,支持的非常好,从而使我们的代码,像操作单机版 Redis 一样简单,轻松实现读写分离。


OK,以上就是 Redis 主从集群的搭建,以及使用 RedisTemplate 操作集群实现读写分离的介绍。但是这中 Redis 集群具有一个缺点,那就 master 节点和 slave 节点是固定的,如果 master 节点宕机,现有的 slave 节点无法选举出一个自动变成 master 节点。后面我们会介绍 Redis 的哨兵集群搭建,以及 Redis 的分片集群搭建,这两种集群可以很好的解决 master 节点宕机问题。

本篇博客的源代码下载地址为:https://files.cnblogs.com/files/blogs/699532/springboot_redis_cluster1.zip

标签:ip,redis,redis1,节点,Redis,主从,RedisTemplate
From: https://www.cnblogs.com/studyjobs/p/17915094.html

相关文章

  • 6.Redis,一站式高性能存储方案
    1.Redis入门Redis是一款基于键值对的NoSQL数据库,它的值支持多种数据结构:字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sortedsets)等。Redis将所有的数据都存放在内存中,所以它的读写性能十分惊人。同时,Redis还可以将内存中的数据以快照或日志的形式保......
  • Redis进阶:Lua初尝试
    Lua是一门脚本语言,可以编写Lua脚本到Redis中执行 【使用Lua脚本的优点】1.减少网络开销。Redis每条命令都需要进行网络传输,特别是命令条数很多的情况。2.原子操作。脚本都会作为一个整体执行,中间不会有其他命令插入。3.复用。会永远存储在Redis中比较类似Sql里面的存储过程......
  • 【转载】Springboot2.x 使用 Redis
    参考https://blog.csdn.net/weixin_43749805/article/details/131399516https://juejin.cn/post/7076244567569203208https://blog.csdn.net/oJingZhiYuan12/article/details/126386904注意classjava.lang.Integercannotbecasttoclasscom.xiaqiuchu.demo.entity.S......
  • redis模糊删除
     客户端连接redis,查看数据 退出 执行exit,退出客户端 执行删除命令(利用xargs命令)redis-cli-apasswordkeys"key*"|xargsredis-cli-apassworddelpassword为密码keys"key*" 即为模糊删除的key查看结果 ......
  • MySQL主从搭建入门
    MySQL主从搭建入门原创 代码新手 代码新手 2023-10-2817:32 发表于上海MySQL之间数据复制的基础是二进制日志文件(binarylogfile)。一台MySQL数据库一旦启用二进制日志后,其作为master,它的数据库中所有操作都会以“事件”的方式记录在二进制日志中,其他数据库作为slave......
  • Redis7 复制
    1、主从复制1.1、常用命令1、主从复制从库操作replicaof主库IP主库端口或者slaveof主库IP主库端口2、取消主从slaveofnoone1.2、主从复制原理和工作流程1、slave启动,同步初请slave启动成功连接到master后会发送一个sync命令slave首次全新连接master,一次完全同步(全......
  • redis实践经验总结
    Redis内存配置当Redis内存不足时,可能导致Key频繁被删除、响应时间变长、QPS不稳定等问题。当内存使用率达到80%以上时就需要我们警惕,并快速定位到内存占用的原因。一般来说,会有以下几种占用内存的情况:数据内存是Redis最主要的部分,存储Redis的键值信息。主要问题是BigKey问题......
  • redis中的hash tag
    在集群模式下,如果lua脚本同时操作多个key,可能会出现:CROSSSLOTKeysinrequestdon'thashtothesameslot的错误。这种情况下,可以通过{...},来指定多个key使用相同的内容进行hash,例如:user:{123}:username和user:{123}:email就会用123去hash,保证落到同一个slot,也就是可以在单个......
  • Redis上层数据类型设计
    StringString即字符串对象,是Redis使用最多的数据类型,其使用key-value结构,key为唯一标识,value为存储内容。value不仅可以是字符串,也可以是数字,包括整数或者浮点数。value最多可以容纳的大小为512MB。>SETnameErickRenOK>SETage19OK>GETname"ErickRen">GETage......
  • nginx+lua+redis实现灰度发布
    前言:授人以鱼不如授人以渔.先学会用,在学原理,在学创造,可能一辈子用不到这种能力,但是不能不具备这种能力。这篇文章主要是沉淀使用nginx+lua+redis实现灰度,当我们具备了这种能力,随时可以基于这种能力和思想调整实现方案:比如nginx+lua+(其他数据源)、nginx+(其他脚本语言)一、灰度......