Redis有三种主要的集群模式,用于在分布式环境中实现高可用性和数据复制。这些集群模式分别是:主从复制(Master-Slave Replication) 、哨兵模式 (Sentinel) 和Redis Cluster模式。
主从复制是Redis最简单的集群模式。这个模式主要是为了解决单点故障的问题,所以将数据复制多个副本中,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务。
主从模式中,包括一个主节点(Master)和一个或多个从节点(Save) 。主节点负责处理所有写操作和读操作而从节点则复制主节点的数据,并且只能处理读操作。当主节点发生故障时,可以将一个从节点升级为主节点,实现故转移(需要手动实现)。
主从复制的优势在于简单易用,适用于读多写少的场景。它提供了数据备份功能,并且可以有很好的扩展性,只要增加更多的从节点,就能让整个集群的读的能力不断提升。
但是主从模式最大的缺点,就是不具备故障自动转移的能力,没有办法做容错和恢复。
主节点和从节点的宕机都会导致客户端部分读写请求失败,需要人工介入让节点恢复或者手动切换一台从节点服务器变成主节点服务器才可以。并且在主节点宕机时,如果数据没有及时复制到从节点,也会导致数据不一致。
主从模式的优点:
主从模式的缺点:
添加Jedis库依赖。如果使用Maven,请在pom.xml文件中添加以下依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisMaster;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPubSub;
import java.util.HashSet;
import java.util.Set;
public class RedisMasterSlaveExample {
public static void main(String[] args) {
// 创建主节点连接池
JedisPool masterPool = new JedisPool("localhost", 6379);
// 从连接池中获取主节点连接
Jedis master = masterPool.getResource();
master.auth("your_password"); // 如果设置了密码,请进行认证
master.flushAll(); // 清空主节点数据,可选操作
// 创建从节点连接池
JedisPool slavePool = new JedisPool("localhost", 6380); // 从节点的端口号可能与主节点不同
// 从连接池中获取从节点连接
Jedis slave = slavePool.getResource();
slave.auth("your_password"); // 如果设置了密码,请进行认证
slave.flushAll(); // 清空从节点数据,可选操作
// 配置主从复制
master.slaveof("yes", "localhost", 6380); // 将当前服务器配置为另一个服务器的从服务器
slave.sync(); // 同步所有键到从节点,也可以选择同步特定键
// 发布和订阅示例(可选)
Set<String> channels = new HashSet<>();
channels.add("testChannel"); // 订阅的频道名称
slave.psubscribe(new JedisPubSub() { // 在从节点上订阅频道消息
@Override
public void onPMessage(String channel, String message) { // 接收到消息时的回调方法
System.out.println("Received message on " + channel + ": " + message);
}
}, channels);
master.publish("testChannel", "Hello from master!"); // 在主节点上发布消息到频道中,从节点会接收到该消息
}
}
为了解决主从模式的无法自动容错及恢复的问题,Redis引入了一种哨兵模式的集群架构。
哨兵模式是在主从复制的基础上加入了哨兵节点。哨兵节点是一种特殊的Redis节点,用于监控主节点和从节点的状态。当主节点发生故障时,哨兵节点可以自动进行故障转移,选择一个合适的从节点升级为主节点,并通知其他从节点和应用程序进行更新。
在原来的主从架构中,引入哨兵节点,其作用是监控Redis主节点和从节点的状态。每个Redis实例都可以作为哨兵节点,通常需要部署多个哨兵节点,以确保故障转移的可靠性。
哨兵节点定期向所有主节点和从节点发送PING命令,如果在指定的时间内未收到PONG响应,哨兵节点会将该书点标记为主观下线。如果一个主节点被多数哨兵节点标记为主观下线,那么它将被标记为客观下线。
当主节点被标记为客观下线时,哨兵节点会触发故障转移过程。它会从所有健康的从节点中选举一个新的主节点并将所有从节点切换到新的主节点,实现自动故障转移。同时,哨兵节点会更新所有客户端的配置,指向新的主节点。
哨兵节点通过发布订阅功能来通知客户端有关主节点状态变化的消息。客户端收到消息后,会更新配置,将新的主节点信息应用于连接池,从而使客户端可以继续与新的主节点进行交互。
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
public class RedisSentinelExample {
public static void main(String[] args) {
// 创建哨兵连接池
String masterName = "mymaster"; // 哨兵配置中的主节点名称
String sentinelHost = "localhost"; // 哨兵节点的地址
int sentinelPort = 26379; // 哨兵节点的端口号
Set<String> sentinels = new HashSet<>();
sentinels.add(sentinelHost + ":" + sentinelPort); // 添加一个或多个哨兵节点地址
JedisSentinelPool sentinelPool = new JedisSentinelPool(masterName, sentinels);
// 从连接池中获取连接
Jedis jedis = sentinelPool.getResource();
jedis.auth("your_password"); // 如果设置了密码,请进行认证
// 执行一些操作,例如设置和获取数据
jedis.set("key", "value");
String value = jedis.get("key");
System.out.println("Value: " + value);
// 关闭连接池和连接
jedis.close();
sentinelPool.close();
}
}
这个集群模式的优点就是为整个集群系统了一种故障转移和恢复的能力。
Redis Cluster是Redis中推荐的分布式集群解决方案,它将数据自动分片到多个节点上,每个节点负责一部分数据。
Redis Cluster采用主从复制模式来提高可用性。每个分片都有一个主节点和多个从节点。主节点负责处理写操作,而从节点负责复制主节点的数据并处理读请求。
Redis Cluster能够自动检测节点的故障。当一个节点失去连接或不可达时,Redis Cluster会尝试将该节点标记为不可用,并从可用的从节点中提升一个新的主节点。
Redis Cluster是适用于大规模应用的解决方案,它提供了更好的横向扩展和容错能力。它自动管理数据分片和故障转移,减少了运维的负担。
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisClusterConnectionHandler;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashSet;
import java.util.Set;
public class RedisClusterExample {
public static void main(String[] args) {
// 创建集群连接池配置
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 设置连接池参数
poolConfig.setMaxTotal(100); // 连接池最大连接数
poolConfig.setMaxIdle(50); // 连接池最大空闲数
poolConfig.setMinIdle(10); // 连接池最小空闲数
poolConfig.setTestOnBorrow(true); // 获取连接时进行有效性检查
poolConfig.setTestOnReturn(true); // 归还连接时进行有效性检查
poolConfig.setTestWhileIdle(true); // 空闲时定期进行有效性检查
// 创建集群连接处理器
JedisClusterConnectionHandler connectionHandler = new JedisClusterConnectionHandler();
Set<HostAndPort> jedisClusterNodes = new HashSet<>();
// 添加集群节点,包括每个节点的地址和端口号
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7380));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7381));
// ...添加更多节点
connectionHandler.setClusterNodes(jedisClusterNodes);
connectionHandler.setPoolConfig(poolConfig);
connectionHandler.setPassword("your_password"); // 如果设置了密码,请进行认证
// 创建集群连接对象并执行操作
JedisCluster jedisCluster = new JedisCluster(connectionHandler);
jedisCluster.set("key", "value"); // 设置键值对
String value = jedisCluster.get("key"); // 获取键值对
System.out.println("Value: " + value);
// 关闭集群连接对象和连接处理器
jedisCluster.close();
connectionHandler.close();
}
}
在这个Demo中,使用JedisCluster类来与Redis Cluster模式进行交互。首先,我们创建了一个JedisPoolConfig对象来配置连接池的参数。然后,我们创建了一个JedisClusterConnectionHandler对象来处理集群节点的连接。接下来,我们将集群节点添加到连接处理器中,并设置连接池配置和密码(如果设置了密码)。最后,我们创建了一个JedisCluster对象来执行操作,并使用set和get方法来设置和获取键值对。在完成后,我们关闭了集群连接对象和连接处理器。请注意,这只是一个简单的示例,实际应用中可能需要更多的配置和错误处理。
Cluster模式的特点是数据分片存诸在不同的节点上,每人节点都可以单独对外提供读写服务。不存在单点故障的问题。