基于zookeeper的统一命名服务及实现

在分布式调度系统中可以使用zookeeper实现统一命名服务,以获得类似于UUID的全局唯一名称。

借助ZNODE顺序节点的特性,本文通过创建临时顺序节点来获得统一命名。使用zookeeper创建顺序节点时,成功创建的每个节点都会返回一个编号,使用该编号以及给定的名称即可生成具有特定含义的统一名称。实现逻辑如下:
1.所有客户端(本文以多线程模拟)都会创建同一个名称的顺序节点
2.节点创建完成后,会返回一个节点名(get_name_completion()中的value返回值)
3.客户端拿到返回值后,可以加上具有特定含义的字符串,即可拼成一个全局唯一的名称。

本文使用zookeeper的C语言客户端,下文代码依赖的头文件以及动态库的生成方式如下:
进入zookeeper 下的src/c/目录下

#./configure
# make & make install

默认头文件安装与 /usr/local/zookeeper/ 动态库位于/usr/local/lib
相关接口介绍如下,具体详见头文件:

//初始化一个zookeeper连接句柄
zhandle_t *zookeeper_init(const char *host, watcher_fn fn,
  int recv_timeout, const clientid_t *clientid, void *context, int flags);
其中 watcher_fn fn是一个全局监视回调函数

//一个异步创建znode的接口,创建完成会调用completion回调函数
int zoo_acreate(zhandle_t *zh, const char *path, const char *value, 
        int valuelen, const struct ACL_vector *acl, int flags,
        string_completion_t completion, const void *data);

//close the zookeeper handle and free up any resources
int zookeeper_close(zhandle_t *zh);

统一命名服务代码实现:

//nameService.cpp
#include 
#include 
#include 
#include  
#include 
#include 

using  namespace std;

const int Clients = 3 ;
int connectd = 0 ;
//创建临时节点,并在完成之后,获得相应的名称
void *Named(void *);
//zookeeper会话的监视函数
void watcher(zhandle_t *zkh,int type, int state, const char *path,void *context);
//创建临时节点成功后的回调函数
void get_name_completion(int rc,const char *value, const void *data);

int main()
{
    pthread_t threadID[Clients];
    int err;
    for(int i = 0 ; i < Clients ;++i)
    {
        err = pthread_create(&threadID[i], NULL, Named, NULL);
        if(err != 0 )
            cout<<"create new thread failed ..." <for(int i = 0 ; i < Clients ;++i)
    {
        err = pthread_join(threadID[i],NULL);
        if(err)
            cout<<"thread join failed ..."<return 0;
}

void *Named(void *arg)
{
    unsigned long idx = pthread_self();
    string host = "localhost:2181";
    zhandle_t *zh;
    zh = zookeeper_init(host.c_str(),watcher,15000,NULL,NULL,0);
    if(NULL == zh)
    {
        cout<<"Init zookeeper handle failed, host:"<return NULL;
    }

    ostringstream oss;
    oss<cout<<"threadID:"<string znode = "/nameservice";
    //异步创建一个ZNODE,节点类型为 临时顺序节点(ZOO_EPHEMERAL | ZOO_SEQUENCE)
    //由于不涉及ACL控制方式,acl设为ZOO_OPEN_ACL_UNSAFE
    //同时通过strdup(oss.str().c_str())将节点内容传入get_name_completion回调函数以供调试
    zoo_acreate(zh,znode.c_str(), oss.str().c_str(), oss.str().length(), &ZOO_OPEN_ACL_UNSAFE,
                ZOO_EPHEMERAL | ZOO_SEQUENCE, get_name_completion, strdup(oss.str().c_str()));
    sleep(5);//等待get_name_competion回调完成
    zookeeper_close(zh);
    return NULL;
}

void watcher(zhandle_t *zkh,int type, int state, const char *path,void *context)
{
    if( ZOO_SESSION_EVENT == type)
    {
        if(state == ZOO_CONNECTED_STATE)
        {
            connectd = 1;
            cout<<"Received a connectd event."<else if( state == ZOO_CONNECTING_STATE){
            if(connectd == 1)
            {
                cout<<"Disconnected."<0 ;
        } else if(state == ZOO_EXPIRED_SESSION_STATE){
            connectd == 0;
            zookeeper_close(zkh);
        }
    }
}

void get_name_completion(int rc,const char *value, const void *data)
{
    if(rc == ZOK)
    {
        //可以用具有特定含义的字符串和value值拼接成名称,此处只用返回值作为名称
        cout<<"threadID:"<<(const char*)data<<",get the name:"<free((void*)data); //strdup会调用malloc,必须手动释放这部分内存
}

你可能感兴趣的:(C++,分布式)