由于时间安排上的原因,这次的代码写的稍微有些简略,只能算是自己对RAFT协议的一个巩固。
实现定义2个节点,使用读取配置文件来获取IP和端口以及节点ID
网络使用boost同步流程 一个线程收 一个线程发送
1 收的线程根据接受的数据 判断是心跳包还是选举请求还是选举请求回复 来更新自己的时间逻辑编号term 更新是否投票isVote 和最新term中那些节点投了自己的选举票map<int,int> // nodeid, term
2 发送的节点每个200MS则轮询一次,根据结点当前状态减少等待时间(等待时间根据节点状态调节为1000ms心跳间隔或者1500-5000的随机选举超时)
现运行看看效果
我们需要两个节点 所以需要将exe和配置文件放入不同的文件夹 如图
启动程序
1 初始两个节点都是follower状态 等待leader发送心跳
2 由于目前无leader 所以两个节点其中之一在随机的超时时间后,发起选举投票
3 之后节点1 成为leader,以1秒(1000ms)的间隔发送心跳包 进入正常状态
4 在状态3 的情况下 关闭folloer状态的节点2 对情况并无影响。leader节点1 会持续尝试连接follower节点2
5 节点2 再次连接 由于leader节点1 发送的心跳term为1 大于新启动节点2的初始化term 0 。所以节点2 会马上成为follower ,接受leader节点1的心跳
6 在状态3 的情况下,如果关闭的是leader节点1,节点2 在一段时候未接受到心跳后,就会广播选举请求,请求自己成为leader,但是由于没有节点与节点2的投票一致,也没有其他的节点选举投票,节点2将持续尝试选举自己成为leader
7 节点1上线后,同意节点2的选举请求,节点2接收超过半数以上的投票,成为leader。开始以1秒间隔发送心跳包。
代码如下
基础结构体:
1 const enum STATUS {
2 LEADER_STATUS = 1,
3 FOLLOWER_STATUS,
4 CANDIDATE_STATUS,
5 PRE_VOTE_STAUS,
6 };
7
8 const enum INFOTYPE {
9 DEFAULT_TYPE = 0,
10 HEART_BREAT_TYPE,
11 VOTE_LEADER_TYPE,
12 VOTE_LEADER_RESP_TYPE,
13
14 };
15
16 typedef struct netInfo {
17 int fromID;
18 int toID;
19 INFOTYPE infotype;
20 int term;
21 int voteId; //选举ID infotype为votetype才有效
22 }NetInfo;
23
24 typedef struct locaInfo {
25 int id;
26 int leaderID;
27 STATUS status;
28 int term;
29 int isVote;
30 int IsRecvHeartbeat;
31 int electionTimeout;
32 std::map<int, int> voteRecord;// id term有此记录表示该term收到该id投取自己一票
33 }LocalInfo;
34
35 typedef struct localInfoWithLock {
36 LocalInfo locInfo;
37 std::mutex m;
38 }LocalInfoWithLock;
基本数据结构
1 #include "RaftManager.h"
2 #include "NetInfoHandler.h"
3 #include "StatusHandler.h"
4 #include <random>
5 #include <functional>
6
7 using namespace std;
8
9 std::shared_ptr<RaftManager> RaftManager::p = nullptr;
10
11 bool RaftManager::Init() {
12 //可以使用json 读取配置
13 ReadConfig cfg("nodeCfg");
14 map<string, string> kv = cfg.Do();
15
16 if (kv.find("ip") == kv.end() || kv.find("portStart") == kv.end() || kv.find("nodeID") == kv.end()) {
17 assert(0);
18 return false;
19 }
20 ip = kv["ip"]; portStart = stoi(kv["portStart"]); nodeID = stoi(kv["nodeID"]);
21 heartbeatTime = 5000;
22 if (kv.find("heartbeatTime") != kv.end())
23 heartbeatTime = stoi(kv["heartbeatTime"]);
24
25 locInfolock.locInfo.id = nodeID; locInfolock.locInfo.leaderID = 0;
26 locInfolock.locInfo.IsRecvHeartbeat = 0; locInfolock.locInfo.isVote = 0;
27 locInfolock.locInfo.electionTimeout = 4000;
28 locInfolock.locInfo.status = FOLLOWER_STATUS;
29 locInfolock.locInfo.voteRecord.clear();
30
31 std::random_device rd;
32 std::default_random_engine engine(rd());
33 std::uniform_int_distribution<> dis(5001, 9000);
34 dice = std::bind(dis, engine);
35
36 return true;
37 }
38
39 void RaftManager::SendFunc(int sendId) {
40 std::shared_ptr<tcp::socket> s = std::make_shared<tcp::socket>((io_service));
41 tcp::resolver resolver(io_service);
42 while (1) {
43 int port = portStart+ sendId;
44
45 try {
46 boost::asio::connect(*s, resolver.resolve({ "127.0.0.1", to_string(port) }));
47 }
48 catch (std::exception& e) {
49 //std::cerr << e.what() << std::endl;
50 continue;
51 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
52 }
53 //============================================================
54 netInfo netinfo;
55 while (1) {
56 q.Take(netinfo);
57 boost::system::error_code ignored_error;
58 boost::asio::write(*s, boost::asio::buffer(&netinfo, sizeof(netinfo)), ignored_error);
59 if (ignored_error) {
60 std::cerr << boost::system::system_error(ignored_error).what() << std::endl;
61 break;
62 }
63
64 std::cout << "\n==========================================================>" << std::endl;
65 std::cout << "Send netinfo" << std::endl;
66 std::cout << "netinf.fromID = " << netinfo.fromID << std::endl;
67 std::cout << "netinf.toID = " << netinfo.toID << std::endl;
68 std::cout << "netinf.infotype = " << netinfo.infotype << std::endl;
69 std::cout << "netinf.term = " << netinfo.term << std::endl;
70 std::cout << "netinf.voteId = " << netinfo.voteId << std::endl << std::endl;
71 std::cout << "<==========================================================" << std::endl;
72 }
73 }
74
75 }
76
77
78 void RaftManager::LoopCheck(LocalInfoWithLock& locInfolock) {
79 int looptime = 200;
80 StatusHandler handler;
81 while (1) {
82 handler.DiapatchByStatus(locInfolock,q);
83 std::this_thread::sleep_for(std::chrono::milliseconds(looptime));
84 }
85
86 return;
87 }
88
89 void RaftManager::RecvNetInfo(tcp::socket sock) {
90 BYTE data[1024] = { 0 };
91 boost::system::error_code error;
92 NetInfo netinf;
93
94 for (;;) {
95 size_t length = sock.read_some(boost::asio::buffer(&netinf, sizeof(netinf)), error);
96 if (error == boost::asio::error::eof)
97 return; // Connection closed cleanly by peer.
98 else if (error) {
99 std::cerr << boost::system::system_error(error).what() << std::endl;// Some other error.
100 return;
101 }
102 if (length != sizeof(netinf)) {
103 std::cerr << __FUNCTION__ << " recv wrong lenth:" << length << std::endl;// Some other error.
104 continue;
105 }
106
107 std::cout << "\n==========================================================>" << std::endl;
108 std::cout << "recv netinfo" << std::endl;
109 std::cout << "netinf.fromID = " << netinf.fromID << std::endl;
110 std::cout << "netinf.toID = " << netinf.toID << std::endl;
111 std::cout << "netinf.infotype = " << netinf.infotype << std::endl;
112 std::cout << "netinf.term = " << netinf.term << std::endl;
113 std::cout << "netinf.voteId = " << netinf.voteId << std::endl << std::endl;
114 std::cout << "<==========================================================" << std::endl;
115
116 NetInfoHandler handler;
117 handler.DispatchByinfoType(netinf,q, locInfolock);
118 }
119
120 }
121
122 bool RaftManager::Go() {
123 if (ip == "" || portStart == 0 || nodeID == 0)
124 return false;
125 try {
126 for (int i = 1; i <= NODE_COUNT; i++) {
127 if (i != nodeID) {
128 std::thread tsend = std::thread(&RaftManager::SendFunc, shared_from_this(),i);
129 tsend.detach();
130 }
131 }
132
133 std::thread tloop = std::thread(&RaftManager::LoopCheck, shared_from_this(), std::ref(locInfolock));
134 tloop.detach();
135
136 int port = portStart + nodeID;
137 tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
138
139 for (;;)
140 {
141 tcp::socket sock(io_service);
142 a.accept(sock);
143 std::cout << "accept\n";
144 std::thread(&RaftManager::RecvNetInfo, shared_from_this(), std::move(sock)).detach();
145 }
146
147 }
148 catch (std::exception& e) {
149 std::cerr << __FUNCTION__ << " : " << e.what() << std::endl;
150 return false;
151 }
152
153 return true;
154 }
读取配置文件和开启网络连接的代码
1 #include "StatusHandler.h"
2 #include "RaftManager.h"
3 #include <iostream>
4
5
6 void StatusHandler::DiapatchByStatus(LocalInfoWithLock& locInfolock, SyncQueue<netInfo>& q) {
7 LocalInfo localInfo;
8 //加锁获取当前状态 决定是否进行发送操作
9 {
10 //加锁获取本地当前状态
11 std::lock_guard<std::mutex> lck(locInfolock.m);
12 localInfo = locInfolock.locInfo;
13 }
14
15 switch (localInfo.status) {
16 case LEADER_STATUS:
17 HandleLeaderSend(locInfolock,q);
18 break;
19 case FOLLOWER_STATUS:
20 HandleFollowerSend(locInfolock,q);
21 break;
22 case CANDIDATE_STATUS:
23 HandleCandidateSend(locInfolock,q);
24 break;
25 default:
26 std::cerr << "Unknown status!" << std::endl;
27 }
28 }
29
30 void StatusHandler::HandleLeaderSend(LocalInfoWithLock& locInfolock, SyncQueue<netInfo>& q) {
31 bool isSendheartbeat = false;
32 int nodeid = 0;
33 int term = 0;
34
35 {
36 std::lock_guard<std::mutex> lck(locInfolock.m);
37 if (locInfolock.locInfo.electionTimeout > 0) {
38 locInfolock.locInfo.electionTimeout -= 200;
39 }
40 //超过时间限制
41 if (locInfolock.locInfo.electionTimeout <= 0 && locInfolock.locInfo.status == LEADER_STATUS) {
42 isSendheartbeat = true;
43 nodeid = locInfolock.locInfo.id;
44 term = locInfolock.locInfo.term;
45 locInfolock.locInfo.electionTimeout = 1000;
46 }
47 }
48 if (isSendheartbeat) {
49 for (int i = 1; i <= NODE_COUNT; i++) {
50 if (i != nodeid) {
51 netInfo netinfo{ nodeid ,i,HEART_BREAT_TYPE ,term,0 };
52 q.Put(netinfo);
53 }
54 }
55 }
56 }
57
58
59 void StatusHandler::HandleFollowerSend(LocalInfoWithLock& locInfolock, SyncQueue<netInfo>& q) {
60 bool isSendVoteNetInfo = false;
61 int nodeid = 0;
62 int term = 0;
63 //加锁获取本地当前状态
64 {
65 //std::cout << "Enter " << __FUNCTION__ << std::endl;
66 std::lock_guard<std::mutex> lck(locInfolock.m);
67 if (locInfolock.locInfo.electionTimeout > 0) {
68 locInfolock.locInfo.electionTimeout -= 200;
69 }
70 //超过时间限制
71 if (locInfolock.locInfo.electionTimeout <= 0) {
72 std::cout << "electionTimeout .change to CANDIDATE_STATUS" << std::endl;
73 if (locInfolock.locInfo.IsRecvHeartbeat == 0) {
74 //心跳超时 切换到选举模式
75 locInfolock.locInfo.term++;
76 locInfolock.locInfo.status = CANDIDATE_STATUS;
77 locInfolock.locInfo.voteRecord.clear();
78 locInfolock.locInfo.voteRecord[locInfolock.locInfo.id] =
79 locInfolock.locInfo.term;
80 isSendVoteNetInfo = true;
81 term = locInfolock.locInfo.term;
82 nodeid = locInfolock.locInfo.id;
83 locInfolock.locInfo.electionTimeout = dice();
84 }
85 else {
86 locInfolock.locInfo.IsRecvHeartbeat = 0;
87 }
88 }
89 else if ( (locInfolock.locInfo.electionTimeout > 0) &&
90 (locInfolock.locInfo.IsRecvHeartbeat == 1) &&
91 (locInfolock.locInfo.status == FOLLOWER_STATUS) )
92 {
93 std::cout << "Check hearbeat OK!!! Clear electionTimeout" << std::endl;
94 locInfolock.locInfo.IsRecvHeartbeat = 0;
95 locInfolock.locInfo.electionTimeout = dice();
96 }
97 }
98
99 if (isSendVoteNetInfo) {
100 for (int i = 1; i <= NODE_COUNT; i++) {
101 if (i != nodeid) {
102 netInfo netinfo{ nodeid ,i,VOTE_LEADER_TYPE ,term,nodeid };
103 q.Put(netinfo);
104 }
105 }
106 }
107
108 }
109
110 void StatusHandler::HandleCandidateSend(LocalInfoWithLock& locInfolock, SyncQueue<netInfo>& q) {
111 bool isSendVoteNetInfo = false;
112 int nodeid = 0;
113 int term = 0;
114 {
115 std::lock_guard<std::mutex> lck(locInfolock.m);
116 if (locInfolock.locInfo.electionTimeout > 0) {
117 locInfolock.locInfo.electionTimeout -= 200;
118 }
119 //超过时间限制
120 if (locInfolock.locInfo.electionTimeout <= 0) {
121 std::cout << "electionTimeout .CANDIDATE_STATUS too" << std::endl;
122 if (locInfolock.locInfo.IsRecvHeartbeat == 0) {
123 //心跳超时 切换到选举模式
124 locInfolock.locInfo.term++;
125 locInfolock.locInfo.status = CANDIDATE_STATUS;
126 locInfolock.locInfo.voteRecord.clear();
127 locInfolock.locInfo.voteRecord[locInfolock.locInfo.id] =
128 locInfolock.locInfo.term;
129 }
130 isSendVoteNetInfo = true;
131 term = locInfolock.locInfo.term;
132 nodeid = locInfolock.locInfo.id;
133 locInfolock.locInfo.electionTimeout = dice();
134 }
135 }
136
137 if (isSendVoteNetInfo) {
138 for (int i = 1; i <= NODE_COUNT; i++) {
139 if (i != nodeid) {
140 netInfo netinfo{ nodeid ,i,VOTE_LEADER_TYPE ,term,nodeid };
141 q.Put(netinfo);
142 }
143 }
144 }
145 }
每间隔200秒就进行状态检测切换,和超时发送回复代码
1 #include "NetInfoHandler.h"
2 #include "RaftManager.h"
3
4 void NetInfoHandler::DispatchByinfoType(const NetInfo& netinf, SyncQueue<netInfo>& q, LocalInfoWithLock& locInfolock) {
5 {
6 std::lock_guard<std::mutex> lck(locInfolock.m);
7 if (netinf.term < locInfolock.locInfo.term)
8 return;
9 if (netinf.term > locInfolock.locInfo.term) {
10 locInfolock.locInfo.term = netinf.term;
11 locInfolock.locInfo.status = FOLLOWER_STATUS;
12 locInfolock.locInfo.isVote = 0;
13 locInfolock.locInfo.IsRecvHeartbeat = 0;
14 locInfolock.locInfo.electionTimeout = dice();
15 locInfolock.locInfo.voteRecord.clear();
16 }
17 }
18 switch (netinf.infotype) {
19 case HEART_BREAT_TYPE:
20 HandleHeartBeatTypeRecv(netinf,q, locInfolock);
21 break;
22 case VOTE_LEADER_TYPE:
23 HandleVoteTypeRecv(netinf,q, locInfolock);
24 break;
25 case VOTE_LEADER_RESP_TYPE:
26 HandleVoteRespTypeRecv(netinf,q, locInfolock);
27 break;
28 default:
29 std::cerr << "Recv Unknown info type." << std::endl;
30 }
31 }
32
33 void NetInfoHandler::HandleVoteRespTypeRecv(const NetInfo& netinf, SyncQueue<netInfo>& q,LocalInfoWithLock& locInfolock) {
34
35 {
36 std::lock_guard<std::mutex> lck(locInfolock.m);
37 if (netinf.term < locInfolock.locInfo.term)
38 return;
39 if (netinf.term > locInfolock.locInfo.term) {
40 locInfolock.locInfo.term = netinf.term;
41 locInfolock.locInfo.status = FOLLOWER_STATUS;
42 locInfolock.locInfo.isVote = 0;
43 locInfolock.locInfo.IsRecvHeartbeat = 0;
44 locInfolock.locInfo.voteRecord.clear();
45 }
46 if (netinf.infotype == VOTE_LEADER_RESP_TYPE && netinf.toID == locInfolock.locInfo.id && netinf.voteId == locInfolock.locInfo.id) {
47 //更新本地map记录
48 locInfolock.locInfo.voteRecord[netinf.fromID] = netinf.term;
49 }
50 int count = 0;
51 std::map<int, int>::iterator it = locInfolock.locInfo.voteRecord.begin();
52 //查看本term的投票是否达半数以上
53 while (it != locInfolock.locInfo.voteRecord.end()) {
54 if (it->second == locInfolock.locInfo.term)
55 count++;
56 it++;
57 }
58 if (count > NODE_COUNT / 2) {
59 //达到半数以上 转化为leader模式 否则继续选举
60 locInfolock.locInfo.leaderID = locInfolock.locInfo.id;
61 locInfolock.locInfo.IsRecvHeartbeat = 0;
62 locInfolock.locInfo.status = LEADER_STATUS;
63 locInfolock.locInfo.electionTimeout = 1000;
64 std::cout << "I am the leader term = " <<
65 locInfolock.locInfo.term << std::endl;
66 }
67 }
68
69 }
70
71 void NetInfoHandler::HandleVoteTypeRecv(const NetInfo& netinf, SyncQueue<netInfo>& q, LocalInfoWithLock& locInfolock) {
72
73 NetInfo respNetInfo;
74 bool isSend = false;
75 {
76 std::lock_guard<std::mutex> lck(locInfolock.m);
77 if (netinf.term < locInfolock.locInfo.term)
78 return;
79 if (netinf.term > locInfolock.locInfo.term) {
80 locInfolock.locInfo.term = netinf.term;
81 locInfolock.locInfo.status = FOLLOWER_STATUS;
82 locInfolock.locInfo.isVote = 0;
83 locInfolock.locInfo.IsRecvHeartbeat = 0;
84 locInfolock.locInfo.voteRecord.clear();
85 }
86 if (locInfolock.locInfo.isVote == 0 && locInfolock.locInfo.status == FOLLOWER_STATUS) {
87 respNetInfo.fromID = locInfolock.locInfo.id;
88 respNetInfo.toID = netinf.fromID;
89 respNetInfo.term = netinf.term;
90 respNetInfo.infotype = VOTE_LEADER_RESP_TYPE;
91 respNetInfo.voteId = netinf.voteId;
92 locInfolock.locInfo.isVote = 1;
93 isSend = true;
94 }
95 else if(locInfolock.locInfo.status == FOLLOWER_STATUS){
96 respNetInfo.fromID = locInfolock.locInfo.id;
97 respNetInfo.toID = netinf.fromID;
98 respNetInfo.term = netinf.term;
99 respNetInfo.infotype = VOTE_LEADER_RESP_TYPE;
100 respNetInfo.voteId = 0;
101 isSend = true;
102 }
103 }
104 if(isSend == true)
105 q.Put(respNetInfo);
106 }
107
108
109 void NetInfoHandler::HandleHeartBeatTypeRecv(const NetInfo& netinf, SyncQueue<netInfo>& q, LocalInfoWithLock& locInfolock) {
110
111 {
112 std::lock_guard<std::mutex> lck(locInfolock.m);
113 if (netinf.term < locInfolock.locInfo.term)
114 return;
115 if (netinf.term > locInfolock.locInfo.term) {
116 locInfolock.locInfo.term = netinf.term;
117 locInfolock.locInfo.status = FOLLOWER_STATUS;
118 locInfolock.locInfo.isVote = 0;
119 locInfolock.locInfo.IsRecvHeartbeat = 0;
120 locInfolock.locInfo.voteRecord.clear();
121 }
122
123 locInfolock.locInfo.IsRecvHeartbeat = 1;
124 }
125 }
收到信息,进行处理以及发送告知自己状态改变的代码