前言

redis使用主从复制,可以使读写分离,缓解服务器压力,增加容错率。


一、准备多份配置文件

redis6379.conf(主节点)

include ./redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb

redis6380.conf redis6381.conf(从节点)

include ./redis.conf
pidfile /var/run/redis_6380.pid
port 6380
dbfilename dump6380.rdb
#replicaof since 5.0
replicaof 192.168.137.208 6379
#主节点的密码
masterauth 21797d7480c1270b848a1524128671b31dcad0725762cf41cc81c21e15fa35b2

在这里插入图片描述

二、依次启动

1.启动

redis-server redis6379.conf 
redis-server redis6380.conf 
redis-server redis6381.conf

2.查看启动情况(配合5关闭使用)

ps -ef|grep redis

3.连接主节点

redis-cli -p 6379

4.查看主从关系

info replication

在这里插入图片描述

5 .关闭多个redis节点

kill -9 4206 4218 4230

在主节点写入值,在从节点能获取到值,就完成了主从复制;

三、哨兵模式

前两步是基础 文档参考

1.增加配置文件

sentinel.conf

#哨兵开启之后会向当前文件写入可覆盖配置
sentinel monitor master 192.168.137.208 6379 1
#redis覆盖部分配置,哨兵开启用户授权
protected-mode no
#user default on nopass sanitize-payload ~* &* +@all
sentinel auth-user master default
sentinel auth-pass master 21797d7480c1270b848a1524128671b31dcad0725762cf41cc81c21e15fa35b2

2.启动哨兵模式

redis-sentinel sentinel.conf

在这里插入图片描述

3.关闭主节点,查看效果

关闭之前
在这里插入图片描述
sentinel监控到的信息(6379被关闭,6381被选为新的主节点)
在这里插入图片描述
切换之后
在这里插入图片描述
主节点切换之后会修改sentinel.conf和redis.conf文件
sentinel known-replica master 127.0.0.1 6380

4.查看当前主节点信息

#连接哨兵监控
redis-cli -p 26379
#简略版(ip和port)
sentinel get-master-addr-by-name master
#详细版(各种信息)
sentinel master master

5.java配置哨兵连接池

application.yml

spring :
  redis:
    sentinel:
      masterName: master
      sentinels: 192.168.137.208:26379

JedisSentinelPoolUtils.java

package com.student.sys.util;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import javax.annotation.PostConstruct;
import java.util.Set;

/**
 * Create by zjg on 2022/11/22
 */
@Configuration
public class JedisSentinelPoolUtils {
    private static JedisSentinelPool jedisSentinelPool;
    @Value("${spring.redis.sentinel.masterName}")
    private  String masterName;
    @Value("${spring.redis.sentinel.sentinels}")
    private Set<String> sentinels;
    @Value("${spring.redis.password}")
    private String password;
    @PostConstruct
    private void init(){
        jedisSentinelPool=new JedisSentinelPool(masterName,sentinels,password);
    }
    public static Jedis getResource() {
        synchronized (JedisSentinelPoolUtils.class){
            if(jedisSentinelPool==null){
                new JedisSentinelPoolUtils().init();
            }
        }
        HostAndPort currentHostMaster = jedisSentinelPool.getCurrentHostMaster();
        System.out.println(String.format("当前主节点ip[%s],port[%s]",currentHostMaster.getHost(),currentHostMaster.getPort()));
        return jedisSentinelPool.getResource();
    }
    public static void close(){
        jedisSentinelPool.close();
    }
}

SpringBootTest.java

package redis;

import com.student.SpringbootStart;
import com.student.sys.util.JedisSentinelPoolUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;

/**
 * Create by zjg on 2022/11/22
 */
@RunWith(SpringRunner.class)
@org.springframework.boot.test.context.SpringBootTest(classes = SpringbootStart.class)
public class SpringBootTest {
    @Test
    public void redisSentinelPoolTest(){
        Jedis jedis= JedisSentinelPoolUtils.getResource();
        System.out.println(jedis.ping());
        jedis.close();
        JedisSentinelPoolUtils.close();
    }
}

在这里插入图片描述

四、搭建集群

文档参考

1.集群节点配置文件

redis6379.conf

include /etc/redis/redis.conf
pidfile "/var/run/redis_6379.pid"
port 6379
dbfilename "dump6379.rdb"
cluster-enabled yes
cluster-config-file node-6379.conf
#在指定的时间内无法访问则认为主节点发生故障,单位为毫秒(10秒)
cluster-node-timeout 10000

redis6379.conf的基础上复制5份出来
例如 : redis6380.conf
使用命令:%s/6379/6380/

2.启动多个节点

redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf
redis-server redis6382.conf
redis-server redis6383.conf
redis-server redis6384.conf
#看一下启动状态
ps -ef|grep redis

3.创建集群

#-a参数为配置密码,未配置可不加
redis-cli --cluster create \
192.168.137.208:6379 \
192.168.137.208:6380 \
192.168.137.208:6381 \
192.168.137.208:6382 \
192.168.137.208:6383 \
192.168.137.208:6384 \
--cluster-replicas 1 \
-a 21797d7480c1270b848a1524128671b31dcad0725762cf41cc81c21e15fa35b2

Can I set the above configuration?

输入 yes

集群配置后的主从关系,M后面的序列号对应S的replicates参数
在这里插入图片描述

4.redis客户端指定集群中任意端口连接到集群

#指定端口号连接到集群
redis-cli -c -p 6379
#查看集群信息
cluster info
#查看集群各个节点信息(这个看起来更明了一些)
cluster nodes
#查看集群插槽信息(主节点)
cluster slots
#计算插槽值(user是key)
cluster keyslot user

每个master最后的参数是slots值范围在0-16383,写入的数据根据key计算出存放在哪个节点服务器
计算出的slots值不在当前服务器的时候,会有个切换的操作,有密码则需要授权
在这里插入图片描述

5.redis集群添加多个值

键名中存在左右大括号的模式,这是Redis Cluster键一个特殊的哈希算法

mset name{user:1001} zhangjg email{user:1001} zhangjg@qq.com.cn

6.故障恢复

当某一段插槽的主从节点全部故障时,其他段插槽仍然保持可用

cluster-require-full-coverage no

7.java连接redis集群

application.yml

spring :
  redis:
    host: 192.168.137.208
    port: 6379
    password: 21797d7480c1270b848a1524128671b31dcad0725762cf41cc81c21e15fa35b2
    #哨兵配置
    sentinel:
      masterName: master
      sentinels: 192.168.137.208:26379
    #集群节点
    cluster:
      clusterNodes: 192.168.137.208:6379,192.168.137.208:6380,192.168.137.208:6381

JedisClusterUtils.java

package com.student.sys.util;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.ConnectionPool;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Create by zjg on 2022/11/29
 */
@Configuration
public class JedisClusterUtils {
    private static JedisCluster jedisCluster ;
    @Value("${spring.redis.cluster.clusterNodes}")
    private String clusterNodes;
    @Value("${spring.redis.user:default}")
    private String user;
    @Value("${spring.redis.password}")
    private String password;
    @PostConstruct
    private void init(){
        Set<HostAndPort> nodes=new HashSet<>();
        Arrays.stream(clusterNodes.split(",")).forEach((addr)->{
            String[] split = addr.split(":");
            HostAndPort hostAndPort=new HostAndPort(split[0],Integer.valueOf(split[1]));
            nodes.add(hostAndPort);
        });
        jedisCluster= new JedisCluster(nodes,user,password);
    }
    public static JedisCluster getResource() {
        synchronized (JedisClusterUtils.class){
            if(jedisCluster==null){
                new JedisClusterUtils().init();
            }
        }
        Map<String, ConnectionPool> clusterNodes = jedisCluster.getClusterNodes();
        return jedisCluster;
    }
}

SpringBootTest.java
测试集群的时候要把JedisSentinelPoolUtils类上的@Configuration注释掉

package redis;

import com.student.SpringbootStart;
import com.student.sys.util.JedisClusterUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.JedisCluster;
import java.util.HashSet;
import java.util.Set;

/**
 * Create by zjg on 2022/11/22
 */
@RunWith(SpringRunner.class)
@org.springframework.boot.test.context.SpringBootTest(classes = SpringbootStart.class)
public class SpringBootTest {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void redisClusterTest(){
        JedisCluster jedisCluster = JedisClusterUtils.getResource();
        String user = jedisCluster.set("user", "zhangjg");
        System.out.println(user);
    }
//    @Test
//    public void redisSentinelPoolTest(){
//        Jedis jedis= JedisSentinelPoolUtils.getResource();
//        System.out.println(jedis.ping());
//        jedis.close();
//        JedisSentinelPoolUtils.close();
//    }
}

在这里插入图片描述
JedisCluster提供了超级多的api,api命令学习


总结

主从复制使读写分离,减轻单个节点的压力,但主节点down掉就会出问题;
哨兵模式在主从复制基础上,当主节点down就会选出新的主节点,基本够用;
集群更加高可用,但可能要考虑更多的问题和场景。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐