raft算法 java

本文深入探讨了Raft一致性算法,并重点讲解了如何使用Java实现这一算法,包括选举过程、日志复制和状态机同步等关键步骤。通过实例代码解析,帮助读者理解Raft算法在实际开发中的应用。
package com.i9i.raft;



import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.Inet4Address;

import java.net.InetAddress;

import java.net.SocketException;

import java.util.Map;

import java.util.Random;

import java.util.TreeMap;

import java.util.concurrent.Callable;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.FutureTask;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicInteger;



import com.alibaba.fastjson2.JSON;

import com.alibaba.fastjson2.JSONObject;

import com.i9i.raft.data.ElectItem;

import com.i9i.raft.data.Message;

import com.i9i.raft.data.VoteItem;

import com.i9i.raft.enums.MessageType;

import com.i9i.raft.enums.NodeType;

import com.i9i.raft.net.UdpNet;



import lombok.Data;

import lombok.experimental.Accessors;



@Data

@Accessors(chain = true)

public class Node {

private Integer id;

private String name;

private String host;

private Integer port;

private volatile ConcurrentHashMap<Integer, AtomicInteger> voteForResult = new ConcurrentHashMap<Integer, AtomicInteger>(

16);

private volatile Integer leaderId;

private volatile Integer term = 0;

private volatile Integer termIndex = 0;

private volatile Integer voteFor = null;

private volatile Long lastHeartBeatTime;

private volatile Long lastElectLeaderTime;

private Map<Integer, String> clusterIps;

private Map<Long, String> log = new TreeMap<>();

private volatile NodeType nodeType = NodeType.Follower;



private volatile FutureTask<Object> electThread;

DatagramSocket datagramSocket = null;

ExecutorService executor=Executors.newSingleThreadExecutor();



public void init() {

new Thread(new MessageReceiveTask(this)).start();

// new Thread(new CheckHeartBeatTask(this)).start();

electThread=new FutureTask<>(new ElectCallable(this));

java.util.Random r = new Random();

try {

TimeUnit.MICROSECONDS.sleep(r.nextLong(50, 50+id*500));

} catch (InterruptedException e) {

e.printStackTrace();

}

if(lastHeartBeatTime!=null&&System.currentTimeMillis()-lastHeartBeatTime<3000*1000)

return;

Executors.newSingleThreadExecutor().submit(electThread);

try {

datagramSocket = new DatagramSocket();

} catch (SocketException e) {



e.printStackTrace();

}



}

public void createElect() throws Exception {

java.util.Random r = new Random();

TimeUnit.MILLISECONDS.sleep(r.nextLong(getId() * 1000L));



setVoteFor(id);

setNodeType(NodeType.Candidate);

setLastElectLeaderTime(System.currentTimeMillis());

Message<ElectItem> electMessage = new Message<>();

electMessage.setMessageType(MessageType.ELECT);

electMessage.setTerm(getTerm() + 1);

electMessage.setTermIndex(1);

electMessage.setFrom(getId());

electMessage.setData(new ElectItem().setTerm(electMessage.getTerm()).setVoteFor(getId()));

System.out.println(getId() +" term:"+getTerm()+ ": create elect leader");

voteForResult.put(id, new AtomicInteger(1));

for (Integer key : getClusterIps().keySet()) {

if(key==id)

continue;

electMessage.setTo(key);

String clusterIp =getClusterIps().get(key);

String[] ipPort = clusterIp.split(":");

UdpNet.send(ipPort[0], Integer.valueOf(ipPort[1]), electMessage);

}



}

public <T> void board(Message<T> message) throws Exception {

byte[] bytes = message.toBytes();





try {

for (Integer key : clusterIps.keySet()) {

message.setTo(key);

String[] ipport = clusterIps.get(key).split(":");

InetAddress addr = Inet4Address.getByName(ipport[0]);



DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, addr, Integer.valueOf(ipport[1]));

datagramSocket.send(packet);

packet=null;

}

} catch (SocketException e) {

throw new RuntimeException(e);

} finally {

// if (datagramSocket != null)

// datagramSocket.close();

}



}

public <T> void send(int nodeId,Message<T> message) throws Exception {

byte[] bytes = message.toBytes();





try {



message.setTo(nodeId);

String[] ipport = clusterIps.get(nodeId).split(":");

InetAddress addr = Inet4Address.getByName(ipport[0]);



DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, addr, Integer.valueOf(ipport[1]));

datagramSocket.send(packet);



} catch (SocketException e) {

throw new RuntimeException(e);

} finally {

// if (datagramSocket != null)

// datagramSocket.close();

// datagramSocket.close();

}



}



class ElectCallable implements Callable<Object> {

private Node node;



ElectCallable(Node node) {

this.node = node;

}



@Override

public Object call() throws Exception {

TimeUnit.SECONDS.sleep(2);

node.createElect();

return null;

}



}



class CheckHeartBeatTask implements RaftTask {

private volatile Node node;



public CheckHeartBeatTask(Node node) {

this.node = node;

}



/**

* Runs this operation.

*/

@Override

public void run() {

boolean first = true;

while (true) {

if (node.getLastHeartBeatTime() == null) {

node.setLastHeartBeatTime(System.currentTimeMillis());

try {



TimeUnit.MILLISECONDS.sleep(500);

first = false;



} catch (InterruptedException e) {

throw new RuntimeException(e);

}

continue;

}

// System.out.println(node.getId()+"time

// gap"+(System.currentTimeMillis()-node.getLastHeartBeatTime()));

if (System.currentTimeMillis() - node.getLastHeartBeatTime() > 30 * 1000 && node.getVoteFor() == null) {

try {

node.createElect();

} catch (Exception e) {

throw new RuntimeException(e);

}

} else {

try {



TimeUnit.MILLISECONDS.sleep(2000);



} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

}

}



// public void createElect() throws Exception {

// java.util.Random r = new Random();

// TimeUnit.MILLISECONDS.sleep(r.nextLong(node.getId() * 1000L));

// if (node.getLastElectLeaderTime() != null

// && System.currentTimeMillis() - node.getLastElectLeaderTime() > 30000) {

// return;

// }

// node.setVoteFor(node.getId());

// node.setNodeType(NodeType.Candidate);

// node.setLastElectLeaderTime(System.currentTimeMillis());

// Message<ElectItem> electMessage = new Message<>();

// electMessage.setMessageType(MessageType.ELECT);

// electMessage.setTerm(node.getTerm() + 1);

// electMessage.setTermIndex(1);

// electMessage.setFrom(node.getId());

// electMessage.setData(new ElectItem().setTerm(electMessage.getTerm()).setVoteFor(node.getId()));

// System.out.println(node.getId() + ": create elect leader");

// for (Integer key : node.getClusterIps().keySet()) {

// electMessage.setTo(key);

// String clusterIp = node.getClusterIps().get(key);

// String[] ipPort = clusterIp.split(":");

// UdpNet.send(ipPort[0], Integer.valueOf(ipPort[1]), electMessage);

// }

//

// }

}



static class MessageReceiveTask implements RaftTask {

private final Node node;

DatagramSocket datagramSocket;



public MessageReceiveTask(Node node) {

this.node = node;



try {

String[] ipPorts = node.getClusterIps().get(node.getId()).split(":");

datagramSocket = new DatagramSocket(Integer.valueOf(ipPorts[1]));

} catch (SocketException e) {

throw new RuntimeException(e);

}

}



/**

* Runs this operation.

*/

@Override

public void run() {



while (true) {

try {

byte[] bytes = new byte[1024];

DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);

datagramSocket.receive(packet);

Message<JSONObject> message = Message.fromBytes(packet.getData(), packet.getLength());

if (!checkMessage(message))

continue;

// System.out.println(

// node.getId() + " nodeType:" + node.getNodeType() + " leaderId:" + node.getLeaderId()

// + "--receive type:" + message.getMessageType().name() + " content:" + message);

switch (message.getMessageType()) {

case HEARTBEAT:

heartBeat(message);

break;

case ELECT:

elect(message);

break;

case VOTE:

vote(message);

break;

default:

System.out.println(message);

}



} catch (Exception e) {

throw new RuntimeException(e);

}

}



}



// 处理收到的心跳信息,执行修改最后心跳时间

private void heartBeat(Message<JSONObject> message) {

if (node.electThread != null) {

node.electThread.cancel(true);

node.electThread=null;

// System.out.println("task cancel");

}

node.setLastHeartBeatTime(System.currentTimeMillis());

node.setTerm(message.getTerm());

node.setTermIndex(message.getTermIndex());

if(node.getLeaderId()==null) {

System.out.println(node.getId()+"收到心跳");

node.setLeaderId(message.getFrom());

node.setVoteFor(null);

}

node.electThread = new FutureTask<>(node.new ElectCallable(node));

try {

node.getExecutor().submit(node.electThread);

// System.out.println("task add");

} catch (Exception e) {

e.printStackTrace();

}

}



private void elect(Message<JSONObject> message) {

if (node.getTerm() > message.getTerm() || node.getTerm() == message.getTerm() && node.getVoteFor() != null)

return;

node.setTerm(message.getTerm());

node.setTermIndex(message.getTermIndex());

node.setLeaderId(null);

JSONObject jo = message.getData();

ElectItem electItem = JSON.to(ElectItem.class, jo);

// 发起投票

node.setVoteFor(electItem.getVoteFor());

Message<VoteItem> voteMessage = new Message<>();

voteMessage.setFrom(node.getId());



voteMessage.setMessageType(MessageType.VOTE);

voteMessage.setTerm(message.getTerm());

voteMessage.setTermIndex(message.getTermIndex() + 1);

VoteItem item = new VoteItem().setLeaderId(electItem.getVoteFor());

voteMessage.setData(item);

try {

node.send(message.getFrom(), voteMessage);

} catch (Exception e) {

e.printStackTrace();

}



}



private void vote(Message<JSONObject> message) {



JSONObject jo = message.getData();

VoteItem item = JSON.to(VoteItem.class, jo);



ConcurrentHashMap<Integer, AtomicInteger> r = node.getVoteForResult();

if (r.get(item.getLeaderId()) != null) {

int voteCount = r.get(item.getLeaderId()).incrementAndGet();

System.out.println(node.getId() + "当前得"+voteCount+"票 from:"+message.getFrom());

if (voteCount > node.getClusterIps().size() / 2) {

System.out.println(node.getId() + "选举成功! leaderId:" + item.getLeaderId());

node.setVoteFor(null);

if (node.getId() == item.getLeaderId() && node.getLeaderId() == null) {

node.setLeaderId(item.getLeaderId());

node.setNodeType(NodeType.Leader);

node.setVoteFor(null);

node.setLastElectLeaderTime(System.currentTimeMillis());

new Thread(new HeartTask(node)).start();

} else if (node.getId() != item.getLeaderId() && node.getNodeType() == NodeType.Leader) {

node.setNodeType(NodeType.Follower);

node.setLeaderId(item.getLeaderId());

node.setVoteFor(null);

node.setLastElectLeaderTime(System.currentTimeMillis());

} else {

node.setNodeType(NodeType.Follower);

node.setLeaderId(item.getLeaderId());

node.setVoteFor(null);

node.setLastElectLeaderTime(System.currentTimeMillis());

}

}



} else {

r.put(item.getLeaderId(), new AtomicInteger(1));

System.out.println(node.getId() + "获得1票 from:"+message.getFrom());

}



}



private boolean checkMessage(Message message) {

if (message.getTerm() < node.getTerm()) {

return false;

}

if (message.getTerm() > node.getTerm()) {



node.setTerm(message.getTerm());

node.setTermIndex(message.getTermIndex());

}

return true;

}



}



}
package com.i9i.raft;

import java.util.LinkedHashMap;
import java.util.Map;

public class Server {
    public static void main(String[] args) {
//        Map<Integer, String> clusterIps = Map.of(1, "127.0.0.1:8891", 2, "127.0.0.1:8892", 3, "127.0.0.1:8893");
        Map<Integer, String> clusterIps = new LinkedHashMap<>();
        int nodes=3;
        for(int i=1;i<=nodes;i++) {
        	clusterIps.put(i, "127.0.0.1:"+(8890+i));
        }
        for (int i = 1; i <=nodes; i++) {
            Node node = new Node();
            node.setId(i);
            node.setClusterIps(clusterIps);
            node.init();

        }
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值