zookeeper探索(4): leaderElection(C语言实现)
上一篇中只是给出了文字描述,本篇中给出具体的代码。
zookeeper的领导选举过程的实现比较简单,体现为创建znode节点,并监听znode节点的变化。具体来说就是:
(1)在跟节点创建"/election"永久性节点;
//创建永久节点/election
string path = "/election";
int ret = zoo_acreate(zkhandle, path.c_str(), "1", 1,
&ZOO_OPEN_ACL_UNSAFE, 0, zkleader_string_completion, "acreate");
if (ret) {
cerr << "Error " << ret << " for acreate" << endl;
return -1;
}
(2)在“/election”节点之下,每个客户端创建属于自己独享的临时顺序节点(即znode节点属性为ZOO_SEQUENCE | ZOO_EPHEMERAL),可以用ip地址也可以用其他的字符串(例如a,b,c);
//创建/election节点的子节点,通过命令行参数argv[1]指定
path = "/election/" + nodename;
ret = zoo_acreate(zkhandle, path.c_str(), "1", 1,
&ZOO_OPEN_ACL_UNSAFE, ZOO_SEQUENCE | ZOO_EPHEMERAL,
zkleader_string_completion, "acreate");
if (ret) {
fprintf(stderr, "Error %d for %s\n", ret, "acreate");
exit(EXIT_FAILURE);
}
(3)获取“/election/“子节点列表,并获取其中的最小节点,判断此最小节点是否为自己;
vector<string> children;
wgetChildren(zkhandle, "/election", children, fn);
if (children.empty()) {
return;
}
for (auto child : children) {
cout << child << endl;
}
string smallestNode = getSmallestNoNode(children);
cout << "znodeName: " << nodename << ", smallest node: " << smallestNode << endl;
if ((!nodename.empty()) && smallestNode == nodename) {
cout << "I'm the leader now" << endl;
} else {
cout << "I'm follower of " << smallestNode << endl;
}
完整代码如下:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <zookeeper/zookeeper.h>
using namespace std;
void leader_watcher(zhandle_t* zh, int type, int state, const char* path, void* watcherCtx)
{
}
void zkleader_string_completion(int rc, const char *name, const void *data)
{
}
void stat_completion(int rc, const struct Stat *stat, const void *data)
{
}
void printIfLeader(zhandle_t* zkhandle, watcher_fn fn);
void get_watcher(zhandle_t* zh, int type, int state, const char* path, void* watcherCtx);
int wgetChildren(zhandle_t* zkhandle, string path, vector<string>& strings, watcher_fn fn);
string getSmallestNoNode(vector<string> nodelist);
bool splitString(vector<string> nodelist, map<string, int>& nodemap);
string nodename = "";
int main(int argc, char** argv)
{
if (argc != 2) {
cout << "Error parameter, useage: ./" << argv[0] << " nodename" << endl;
return -1;
}
//初始化需要的参数
nodename = argv[1];
string servs = "172.17.0.2:2181"; //",172.17.0.3:2181,172.17.0.4:2181";
int timeout = 300;
//初始化zookeeper句柄
zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
zhandle_t* zkhandle = zookeeper_init(servs.c_str(), leader_watcher, timeout, 0, NULL, 0);
if (zkhandle == NULL) {
cerr << "Error when connecting to zookeeper servers..." << endl;
return -1;
}
//创建永久节点/election
string path = "/election";
int ret = zoo_acreate(zkhandle, path.c_str(), "1", 1,
&ZOO_OPEN_ACL_UNSAFE, 0, zkleader_string_completion, "acreate");
if (ret) {
cerr << "Error " << ret << " for acreate" << endl;
return -1;
}
//创建/election节点的子节点,通过命令行参数argv[1]指定
path = "/election/" + nodename;
ret = zoo_acreate(zkhandle, path.c_str(), "1", 1,
&ZOO_OPEN_ACL_UNSAFE, ZOO_SEQUENCE | ZOO_EPHEMERAL,
zkleader_string_completion, "acreate");
if (ret) {
fprintf(stderr, "Error %d for %s\n", ret, "acreate");
exit(EXIT_FAILURE);
}
printIfLeader(zkhandle, get_watcher);
getchar();
//释放zookeeper句柄
zookeeper_close(zkhandle);
return 0;
}
void printIfLeader(zhandle_t* zkhandle, watcher_fn fn)
{
vector<string> children;
wgetChildren(zkhandle, "/election", children, fn);
if (children.empty()) {
return;
}
for (auto child : children) {
cout << child << endl;
}
string smallestNode = getSmallestNoNode(children);
cout << "znodeName: " << nodename << ", smallest node: " << smallestNode << endl;
if ((!nodename.empty()) && smallestNode == nodename) {
cout << "I'm the leader now" << endl;
} else {
cout << "I'm follower of " << smallestNode << endl;
}
}
void get_watcher(zhandle_t* zh, int type, int state, const char* path, void* watcherCtx)
{
cout << "node list changing, type:" << type << ", state: " << state << ", path: " << path;
printIfLeader(zh, get_watcher);
}
int wgetChildren(zhandle_t* zkhandle, string path, vector<string>& children, watcher_fn fn)
{
struct String_vector strChildren;
int ret = zoo_wget_children(zkhandle, path.c_str(), fn, NULL, &strChildren);
if (ret != ZOK) {
cerr << "Error " << ret << " for wgetChilren." << endl;
} else {
for (int i = 0; i < strChildren.count; i++) {
children.push_back(strChildren.data[i]);
}
}
return ret;
}
string getSmallestNoNode(vector<string> nodelist)
{
if (nodelist.empty()) {
return "";
}
map<string, int> nodemap; //<nodeName, nodeNumber>
splitString(nodelist, nodemap);
if (nodemap.size() == 1) {
return nodemap.begin()->first;
}
int minNum = 999999999;
string minName = "";
for (auto node : nodemap) {
if (minNum > node.second) {
minNum = node.second;
minName = node.first;
}
}
return minName;
}
bool splitString(vector<string> nodelist, map<string, int>& nodemap)
{
string prefix, postfix;
int sn;
for (auto node : nodelist) {
prefix = node.substr(0, node.length() - 10);
postfix = node.substr(node.length() - 10, node.length());
sn = atoi(postfix.c_str());
cout << prefix << ", " << postfix << ", " << sn << endl;
nodemap[prefix] = sn;
}
return true;
}
完整netbeans工程代码见github:git@github.com:sunsmiles/leaderelection.git
发表评论: