Redis Cluster 的高容错性是怎么做到的?说白了,就是主从复制、自动故障转移和 Gossip 协议这三板斧。它们配合起来,确保集群里某个节点出问题也不会让整个服务挂掉。下面拆开来讲,顺便用 Ja va 代码演示一下实现逻辑。 1. 主从复制(Master-Sla ve Replicatio
Redis Cluster 的高容错性是怎么做到的?说白了,就是主从复制、自动故障转移和 Gossip 协议这三板斧。它们配合起来,确保集群里某个节点出问题也不会让整个服务挂掉。下面拆开来讲,顺便用 Ja va 代码演示一下实现逻辑。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
这是最基础的高可用保障。每个主节点可以挂一到多个从节点,数据实时同步过去。一旦主节点挂了,从节点就能顶上,顶多丢一小部分还没来得及同步的数据。从代码角度看,就是定义节点角色和关联关系。
import ja va.util.ArrayList;
import ja va.util.List;
class ClusterNode {
String name;
String ip;
int port;
boolean isMaster;
ClusterNode master;
ClusterNode(String name, String ip, int port, boolean isMaster, ClusterNode master) {
this.name = name;
this.ip = ip;
this.port = port;
this.isMaster = isMaster;
this.master = master;
}
@Override
public String toString() {
return "Node " + name + ": " + ip + ":" + port + ", Role: " + (isMaster "Master" : "Sla ve");
}
}
class Cluster {
List nodes = new ArrayList<>();
void addNode(String name, String ip, int port, boolean isMaster, ClusterNode master) {
nodes.add(new ClusterNode(name, ip, port, isMaster, master));
}
void printNodes() {
for (ClusterNode node : nodes) {
System.out.println(node);
}
}
}
public class RedisClusterDemo {
public static void main(String[] args) {
Cluster cluster = new Cluster();
ClusterNode master1 = new ClusterNode("master1", "192.168.1.1", 6379, true, null);
cluster.addNode(master1.name, master1.ip, master1.port, master1.isMaster, master1.master);
cluster.addNode("sla ve1", "192.168.1.2", 6379, false, master1);
cluster.printNodes();
}
}
主节点挂了,从节点不能傻等着,得自动升主。这个过程中,其他节点需要协同工作,保证数据完整性不出乱子。下面的代码模拟了心跳检测和故障转移的简单逻辑:超过3秒没收到主节点心跳,就认定它挂了,然后找一个从节点转正。
import ja va.util.ArrayList;
import ja va.util.List;
import ja va.util.Timer;
import ja va.util.TimerTask;
class ClusterNode {
String name;
String ip;
int port;
boolean isMaster;
ClusterNode master;
long lastHeartbeat;
boolean isFailed;
ClusterNode(String name, String ip, int port, boolean isMaster, ClusterNode master) {
this.name = name;
this.ip = ip;
this.port = port;
this.isMaster = isMaster;
this.master = master;
this.lastHeartbeat = System.currentTimeMillis();
this.isFailed = false;
}
void sendHeartbeat() {
System.out.println("Sending heartbeat to node " + name);
lastHeartbeat = System.currentTimeMillis();
}
void checkHeartbeat() {
long now = System.currentTimeMillis();
if (now - lastHeartbeat > 3000) {
System.out.println("Node " + name + " is not responding");
isFailed = true;
}
}
@Override
public String toString() {
return "Node " + name + ": " + ip + ":" + port + ", Role: " + (isMaster "Master" : "Sla ve");
}
}
class Cluster {
List nodes = new ArrayList<>();
void addNode(String name, String ip, int port, boolean isMaster, ClusterNode master) {
nodes.add(new ClusterNode(name, ip, port, isMaster, master));
}
void handleFailover() {
for (ClusterNode node : nodes) {
if (node.isMaster && node.isFailed) {
for (ClusterNode sla ve : nodes) {
if (sla ve.master == node) {
System.out.println("Failover: promoting sla ve node " + sla ve.name + " to master");
sla ve.isMaster = true;
sla ve.master = null;
node.isMaster = false;
return;
}
}
}
}
}
void simulateCluster() {
Timer timer = new Timer(true);
TimerTask task = new TimerTask() {
@Override
public void run() {
for (ClusterNode node : nodes) {
if (node.isMaster && !node.isFailed) {
node.sendHeartbeat();
} else {
node.checkHeartbeat();
if (node.isFailed && node.isMaster) {
handleFailover();
}
}
}
}
};
timer.scheduleAtFixedRate(task, 0, 1000);
}
void printNodes() {
for (ClusterNode node : nodes) {
System.out.println(node);
}
}
}
public class RedisClusterDemo {
public static void main(String[] args) throws InterruptedException {
Cluster cluster = new Cluster();
ClusterNode master1 = new ClusterNode("master1", "192.168.1.1", 6379, true, null);
cluster.addNode(master1.name, master1.ip, master1.port, master1.isMaster, master1.master);
cluster.addNode("sla ve1", "192.168.1.2", 6379, false, master1);
cluster.addNode("sla ve2", "192.168.1.3", 6379, false, master1);
cluster.printNodes();
cluster.simulateCluster();
Thread.sleep(10000);
master1.isFailed = true;
Thread.sleep(20000);
}
}
光有主从和自动切换还不够——整个集群必须对节点状态达成共识。Gossip 协议就是干这个的:每个节点定期给其他节点广播心跳信息,互相知道谁还活着。如果某个节点被多数节点报告不可达,那它就会被标记为失败,触发故障转移。下面的代码模拟了 gossip 交互:节点之间互相发送和接收心跳,同时检测超时,一旦发现主节点挂了就自动切换。
import ja va.util.ArrayList;
import ja va.util.List;
import ja va.util.Timer;
import ja va.util.TimerTask;
class ClusterNode {
String name;
String ip;
int port;
boolean isMaster;
ClusterNode master;
long lastHeartbeat;
boolean isFailed;
ClusterNode(String name, String ip, int port, boolean isMaster, ClusterNode master) {
this.name = name;
this.ip = ip;
this.port = port;
this.isMaster = isMaster;
this.master = master;
this.lastHeartbeat = System.currentTimeMillis();
this.isFailed = false;
}
void sendHeartbeat() {
System.out.println("Sending heartbeat from node " + name);
lastHeartbeat = System.currentTimeMillis();
}
void receiveHeartbeat() {
System.out.println("Received heartbeat at node " + name);
lastHeartbeat = System.currentTimeMillis();
isFailed = false;
}
void checkHeartbeat() {
long now = System.currentTimeMillis();
if (now - lastHeartbeat > 3000) {
System.out.println("Node " + name + " is not responding");
isFailed = true;
}
}
@Override
public String toString() {
return "Node " + name + ": " + ip + ":" + port + ", Role: " + (isMaster "Master" : "Sla ve");
}
}
class Cluster {
List nodes = new ArrayList<>();
void addNode(String name, String ip, int port, boolean isMaster, ClusterNode master) {
nodes.add(new ClusterNode(name, ip, port, isMaster, master));
}
void handleFailover(ClusterNode failedNode) {
for (ClusterNode node : nodes) {
if (node.master == failedNode && !node.isFailed) {
System.out.println("Failover: promoting sla ve node " + node.name + " to master");
node.isMaster = true;
node.master = null;
failedNode.isMaster = false;
return;
}
}
}
void gossip() {
for (ClusterNode node : nodes) {
if (!node.isFailed) {
for (ClusterNode peer : nodes) {
if (peer != node) {
peer.receiveHeartbeat();
}
}
} else {
handleFailover(node);
}
}
}
void simulateCluster() {
Timer timer = new Timer(true);
TimerTask heartbeatTask = new TimerTask() {
@Override
public void run() {
for (ClusterNode node : nodes) {
if (!node.isFailed) {
node.sendHeartbeat();
}
}
}
};
TimerTask gossipTask = new TimerTask() {
@Override
public void run() {
gossip();
}
};
timer.scheduleAtFixedRate(heartbeatTask, 0, 1000);
timer.scheduleAtFixedRate(gossipTask, 0, 1000);
}
void printNodes() {
for (ClusterNode node : nodes) {
System.out.println(node);
}
}
}
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述