文章目录
前言
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就会选出新的主节点,基本够用;
集群更加高可用,但可能要考虑更多的问题和场景。