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
发表评论: