Redis 主从复制

2022-09-01  本文已影响0人  右耳菌

1. 主从复制介绍

1.1 什么是主从复制?
1.2 为什么要主从复制?
1.3 主从复制应用场景分析

2. 搭建主从复制

主Redis Server以普通模式启动,主要是启动从服务器的方式

2.1 第一种方式:命令行
#连接需要实现从节点的redis,执行下面的命令
slaveof [ip] [port]
2.2 第二种方式:redis.conf配置文件
# 配置文件中增加
slavepof [ip] [port]
# 从服务器是否只读(默认yes)
slave-read-only yes
2.3 退出主从集群的方式
slaveof no one

注意: 因为文化差异的原因,新的版本可能会将slaveof变为replicaof,但是其实是一样的。


3. 检查主从复制

192.168.1.7:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:4fa1246eb96e7ad381cd21ab0f1f5a267d1a1cec
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210
192.168.1.7:6378> info replication
# Replication
role:slave
master_host:192.168.1.7
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1662020523
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:101535bfbefc8c9858ff46bad42b8439c87295eb
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
(3.74s)

注意: 如果从服务器尝试复制数据时,提示以下错误,那么可能是缺少了文件的读取权限,需要使用sudo 或者 切换到 root用户启动!

Opening the temp file needed for MASTER <-> REPLICA synchronization: Permission denied

4. 主从复制流程

  1. 从服务器通过psync命令发送服务器已有的同步进度(同步源ID、同步进度offset)
  2. master收到请求,同步源为当前master,则根据偏移量增量同步
  3. 同步源非当前master,则进入全量同步: master生成rdb,传输到slave,加载到slave内存

5. 主从复制核心知识


6. 主从复制应用场景


7. 主从复制的注意事项


8. 例子

首先记得先把lettuce依赖加入pom

        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>${lettuce.version}</version>
        </dependency>

1. 非读写分离方式
创建ReplicationRedisAppConfig.java

package cn.lazyfennnec.cache.redis;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

@Configuration
@Profile("replication") // 主从模式
class ReplicationRedisAppConfig {

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(redisConnectionFactory);
        return stringRedisTemplate;
    }


    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        // 假设master:192.168.100.241    slave:192.168.100.242
        // 默认slave只能进行读取,不能写入
        // 如果你的应用程序需要往redis写数据,建议连接master
        // 其实本地的redis都是在同一个服务器上的,分别为
        // 1. master 192.168.1.7 6379
        // 2. slave  192.168.1.7 6378
        return new LettuceConnectionFactory(new RedisStandaloneConfiguration("192.168.1.7", 6379));
    }
}

2. 读写分离的方式
创建ReplicationRWRedisAppConfig.java

package cn.lazyfennec.cache.redis;

import io.lettuce.core.ReadFrom;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

@Configuration
@Profile("replication-rw") // 主从 - 读写分离模式
class ReplicationRWRedisAppConfig {

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(redisConnectionFactory);
        return stringRedisTemplate;
    }

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        System.out.println("使用读写分离版本");
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                .readFrom(ReadFrom.SLAVE_PREFERRED)
                .build();
        // 此处
        RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration("192.168.1.7", 6378);
        return new LettuceConnectionFactory(serverConfig, clientConfig);
    }
}

3. Service实现类

package cn.lazyfennec.cache.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class ReplicationExampleService {
    @Autowired
    private StringRedisTemplate template;

    public void setByCache(String userId, String userInfo) {
        template.opsForValue().set(userId, userInfo);
    }

    public String getByCache(String userId) {
        return template.opsForValue().get(userId);
    }
}

4. 测试代码

package cn.lazyfennec.cache.redis;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
@ActiveProfiles("replication") // 激活主从复制的配置
public class ReplicationTests {
    @Autowired
    ReplicationExampleService replicationExampleService;

    @Test
    public void setTest() {
        replicationExampleService.setByCache("neco", "hahhhhh");
    }
}
package cn.lazyfennec.cache.redis;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
@ActiveProfiles("replication-rw") // 激活主从集群-读写分离的配置
public class ReplicationRWTests {
    @Autowired
    ReplicationExampleService replicationExampleService;

    @Test
    public void setTest() {
        replicationExampleService.setByCache("neco", "xxxx");
        String result = replicationExampleService.getByCache("neco");
        System.out.println("从缓存中读取到数据:" + result);
    }
}

如果觉得有收获,欢迎点赞和评论,更多知识,请点击关注查看我的主页信息哦~

上一篇 下一篇

猜你喜欢

热点阅读