Zookeeper场景实践:(4)命名服务

1.基本介绍

命名服务是指通过指定的名字来获取资源或者服务的地址,提供者的信息。利用Zookeeper很容易创建一个全局的路径,而这个路径就可以作为一个名字,它可以指向集群中的集群,提供的服务的地址,远程对象等。简单来说使用Zookeeper做命名服务就是用路径作为名字,路径上的数据就是其名字指向的实体。

阿里巴巴集团开源的分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务地址列表。在Dubbo实现中:

服务提供者在启动的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址,这个操作就完成了服务的发布

服务消费者启动的时候,订阅/dubbo/{serviceName}/providers目录下的提供者URL地址, 并向/dubbo/{serviceName} /consumers目录下写入自己的URL地址。

注意,所有向ZK上注册的地址都是临时节点,这样就能够保证服务提供者和消费者能够自动感应资源的变化。

另外,Dubbo还有针对服务粒度的监控,方法是订阅/dubbo/{serviceName}目录下所有提供者和消费者的信息。

场景实践

上面的介绍已经满详细,实际实现起来也比较容易。下面讲讲模拟程序的主要特点。模拟程序有3个参数

  • -m 程序运行的方式,指定是服务提供者provider还是服务消费者consumer,或者是服务监控者monitor
  • -n 表示服务名称
  • -s 表示Zookeeper的服务地址IP:PORT
    运行命令如下:
    服务提供者:
    >nameservice -m provider -n query_bill -s172.17.0.36:2181
    服务消费者:
    >nameservice -m consumer -n query_bill -s172.17.0.36:2181
    服务监控者:
    >nameservice -m monitor -n query_bill -s172.17.0.36:2181

第一条命令是启动一个服务提供进程,它提供了一个名为query_bill的服务,程序首次运行时会创建
/NameService,/NameService/query_bill,/NameService/query_bill/provider,/NameService/query_bill/consumer/等几个路径。然后在服务提供进程在/NameService/query_bill/provider下创建临时序列节点.

第二条命令是启动一个服务消费进程,它在/NameService/query_bill/consumer/下创建临时序列节点,并watch/NameService/query_bill/provider的子节点变化事件,及时更新provider列表。

第三条命令是启动一个服务监控进程,它watch
/NameService/query_bill/provider
,/NameService/query_bill/consumer/两个路径的子节点变化,及时更新provider列表和comsumer列表。

完整的代码如下:

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include"zookeeper.h"
#include"zookeeper_log.h"  

enum MODE{PROVIDER_MODE,CONSUMER_MODE,MONITOR_MODE} g_mode;
char g_host[512]= "172.17.0.36:2181";
char g_service[512]={ 0 };
char g_path[512]="/NameService";

//watch function when child list changed
void zktest_watcher_g(zhandle_t* zh, int type, int state, const char* path, void* watcherCtx);
//show all process ip:pid
void show_list(zhandle_t *zkhandle,const char *path);
//if success,the g_mode will become MODE_MONITOR
void choose_mater(zhandle_t *zkhandle,const char *path);
//get localhost ip:pid
void getlocalhost(char *ip_pid,int len);

void print_usage();
void get_option(int argc,const char* argv[]);

/**********unitl*********************/
void print_usage()
{
    printf("Usage : [nameservice] [-h] [-m mode] [-n servicename] [-s ip:port] \n");
    printf("        -h Show help\n");
    printf("        -m set mode:provider,consumer,monitor\n");
    printf("        -n set servicename\n");
    printf("        -s server ip:port\n");
    printf("For example:\n");
    printf("    nameservice -m provider -n query_bill -s172.17.0.36:2181 \n");
    printf("    nameservice -m consumer -n query_bill -s172.17.0.36:2181 \n");
    printf("    nameservice -m monitor  -n query_bill -s172.17.0.36:2181 \n");
}

void get_option(int argc,const char* argv[])
{
    extern char    *optarg;
    int            optch;
    int            dem = 1;
    const char    optstring[] = "hm:n:s:";

    while((optch = getopt(argc , (char * const *)argv , optstring)) != -1 )
    {
        switch( optch )
        {
        case 'h':
            print_usage();
            exit(-1);
        case '?':
            print_usage();
            printf("unknown parameter: %c\n", optopt);
            exit(-1);
        case ':':
            print_usage();
            printf("need parameter: %c\n", optopt);
            exit(-1);
        case 'm':
            if (strcasecmp(optarg,"provider") == 0){
                g_mode = PROVIDER_MODE;
            }else if (strcasecmp(optarg,"consumer") == 0){
                g_mode = CONSUMER_MODE;
            }else{
                g_mode = MONITOR_MODE;
            }
            break;
        case 'n':
            strncpy(g_service,optarg,sizeof(g_service));
            break;
        case 's':
            strncpy(g_host,optarg,sizeof(g_host));
            break;
        default:
            break;
        }
    }
}
void zktest_watcher_g(zhandle_t* zh, int type, int state, const char* path, void* watcherCtx)
{
/*
    printf("watcher event\n");
    printf("type: %d\n", type);
    printf("state: %d\n", state);
    printf("path: %s\n", path);
    printf("watcherCtx: %s\n", (char *)watcherCtx);
*/  

    if(type == ZOO_CHILD_EVENT &&
       state == ZOO_CONNECTED_STATE &&
       g_mode == CONSUMER_MODE){

        printf("providers list changed!\n");
        show_list(zh,path);
    }else if(type == ZOO_CHILD_EVENT &&
             state == ZOO_CONNECTED_STATE &&
             g_mode == MONITOR_MODE){

        printf("providers or consumers list changed!\n");

        char child_path[512];
        printf("providers:\n");
        sprintf(child_path,"%s/%s/provider",g_path,g_service);
        show_list(zh,child_path);

        printf("consumers:\n");
        sprintf(child_path,"%s/%s/consumer",g_path,g_service);
        show_list(zh,child_path);
    }
}
void getlocalhost(char *ip_pid,int len)
{
    char hostname[64] = {0};
    struct hostent *hent ;

    gethostname(hostname,sizeof(hostname));
    hent = gethostbyname(hostname);

    char * localhost = inet_ntoa(*((struct in_addr*)(hent->h_addr_list[0])));

    snprintf(ip_pid,len,"%s:%d",localhost,getpid());
}

void show_list(zhandle_t *zkhandle,const char *path)
{

    struct String_vector procs;
    int i = 0;
    char localhost[512]={0};

    getlocalhost(localhost,sizeof(localhost));

    int ret = zoo_get_children(zkhandle,path,1,&procs);

    if(ret != ZOK){
        fprintf(stderr,"failed to get the children of path %s!\n",path);
    }else{
        char child_path[512] ={0};
        char ip_pid[64] = {0};
        int ip_pid_len = sizeof(ip_pid);
        printf("--------------\n");
        printf("ip\tpid\n");
        for(i = 0; i < procs.count; ++i){
            sprintf(child_path,"%s/%s",path,procs.data[i]);
            //printf("%s\n",child_path);
            ret = zoo_get(zkhandle,child_path,0,ip_pid,&ip_pid_len,NULL);
            if(ret != ZOK){
                fprintf(stderr,"failed to get the data of path %s!\n",child_path);
            }else if(strcmp(ip_pid,localhost)==0){
                printf("%s(Master)\n",ip_pid);
            }else{
                printf("%s\n",ip_pid);
            }
        }
    }

    for(i = 0; i < procs.count; ++i){
        free(procs.data[i]);
        procs.data[i] = NULL;
    }
}
int create(zhandle_t *zkhandle,const char *path,const char *ctx,int flag)
{
    char path_buffer[512];
    int bufferlen=sizeof(path_buffer);  

    int ret = zoo_exists(zkhandle,path,0,NULL);
    if(ret != ZOK){
        ret = zoo_create(zkhandle,path,ctx,strlen(ctx),
                          &ZOO_OPEN_ACL_UNSAFE,flag,
                          path_buffer,bufferlen);
        if(ret != ZOK){
            fprintf(stderr,"failed to create the path %s!\n",path);
        }else{
            printf("create path %s successfully!\n",path);
        }
    }

    return ZOK;
}

int main(int argc, const char *argv[])
{
    int timeout = 30000;
    char path_buffer[512];
    int bufferlen=sizeof(path_buffer);
    int ret = 0;
    zoo_set_debug_level(ZOO_LOG_LEVEL_ERROR); //设置日志级别,避免出现一些其他信息  

    get_option(argc,argv);

    zhandle_t* zkhandle = zookeeper_init(g_host,zktest_watcher_g, timeout, 0, (char *)"NameService Test", 0);  

    if (zkhandle ==NULL)
    {
        fprintf(stderr, "Error when connecting to zookeeper servers...\n");
        exit(EXIT_FAILURE);
    }  

    create(zkhandle,g_path,"NameService Test",0);

    sprintf(path_buffer,"%s/%s",g_path,g_service);
    create(zkhandle,path_buffer,"NameService Test",0);

    sprintf(path_buffer,"%s/%s/provider",g_path,g_service);
    create(zkhandle,path_buffer,"NameService Test",0);

    sprintf(path_buffer,"%s/%s/consumer",g_path,g_service);
    create(zkhandle,path_buffer,"NameService Test",0);

    if(g_mode == PROVIDER_MODE){

        char localhost[512]={0};
        getlocalhost(localhost,sizeof(localhost));

        char child_path[512];
        sprintf(child_path,"%s/%s/provider/",g_path,g_service);
        ret = zoo_create(zkhandle,child_path,localhost,strlen(localhost),
                          &ZOO_OPEN_ACL_UNSAFE,ZOO_SEQUENCE|ZOO_EPHEMERAL,
                          path_buffer,bufferlen);
        if(ret != ZOK){
            fprintf(stderr,"failed to create the child_path %s,buffer:%s!\n",child_path,path_buffer);
        }else{
            printf("create child path %s successfully!\n",path_buffer);
        }

    }else if (g_mode == CONSUMER_MODE){

        char localhost[512]={0};
        getlocalhost(localhost,sizeof(localhost));

        char child_path[512];
        sprintf(child_path,"%s/%s/consumer/",g_path,g_service);
        ret = zoo_create(zkhandle,child_path,localhost,strlen(localhost),
                          &ZOO_OPEN_ACL_UNSAFE,ZOO_SEQUENCE|ZOO_EPHEMERAL,
                          path_buffer,bufferlen);
        if(ret != ZOK){
            fprintf(stderr,"failed to create the child_path %s,buffer:%s!\n",child_path,path_buffer);
        }else{
            printf("create child path %s successfully!\n",path_buffer);
        }

        sprintf(child_path,"%s/%s/provider",g_path,g_service);
        show_list(zkhandle,child_path);

    }else if(g_mode == MONITOR_MODE){
        char child_path[512];
        printf("providers:\n");
        sprintf(child_path,"%s/%s/provider",g_path,g_service);
        show_list(zkhandle,child_path);

        printf("consumers:\n");
        sprintf(child_path,"%s/%s/consumer",g_path,g_service);
        show_list(zkhandle,child_path);
    }

    getchar();

    zookeeper_close(zkhandle); 

    return 0;
}
时间: 2024-10-02 10:52:09

Zookeeper场景实践:(4)命名服务的相关文章

ZooKeeper场景实践:(1)准备工作

ZooKeeper是一个高可用的分布式数据管理与系统协调框架.保证了分布式环境中数据的强一致性,也正是基于这样的特性,使得ZooKeeper解决很多分布式问题. 有人认为ZooKeeper之于分布式的意义正如同lex/yacc之于编译的意义.我们知道lex/yacc是一套强大的语法编译工具.使用lex/yacc可以很轻松的完成许多语法规则的编写.同样道理,Zookeeper作为一个分布式的数据管理和协调框架,没有它依然可以做分布式,但是有了它,你的分布式会更轻松. 本系列文章主要是从学习的角度对

ZooKeeper场景实践:(7) 分布式锁

1.基本介绍 分布式锁是控制分布式系统之间同步访问共享资源的一种方式,需要互斥来防止彼此干扰来保证一致性.利用Zookeeper的强一致性可以完成锁服务.Zookeeper的官方文档是列举了两种锁,独占锁和共享锁.独占锁保证任何时候都只有一个进程能或者资源的读写权限.共享锁可以同时有多个读,但是同一时刻最多只能有一个写,读和写是互斥的. 2.场景分析 我们准备来实现互斥的锁,按照官网的思路,给定一个锁的路径,如/Lock,所有要申请这个锁的进程都在/Lock目录下创建一个/Lock/lock-的

Zookeeper场景实践:(8) 分布式队列

1.基本介绍 按照ZooKeeper典型应用场景一览里的说法,分布式队列有两种,一种是常规的先进先出队列,另一种是要等到队列成员聚齐之后的才统一按序执行. 第二种队列可以先建立一个/queue,赋值为n,表达队列的大小.然后每个队列成员加入时,就判断是否达到队列要求的大小,如果是可以进行下一步动作,否则继续等待队列成员的加入.比较典型的情况是,当一个大的任务可能需要很多的子任务完成才能开始进行. 比如汇总账单的时候,就必须先将用户的消费数据,积分数据等都统计完成后才能开始.汇总账单的程序建立一个

Zookeeper场景实践:(5)分布式通知/协调

1.基本介绍 通知/协调机制通常有两种方式. 系统调度模式:操作人员发送通知实际是通过控制台改变某个节点的状态,然后Zookeeper将这些变化发送给注册了这个节点的Watcher的所有客户端. 工作汇报模式:这个情况是每个工作进程都在某个目录下创建一个临时节点,并携带工作的进度数据.这样汇总的进程可以监控目录子节点的变化获得工作进度的实时的全局情况. 总的来说,利用Zookeeper的watcher注册和异步通知功能,通知的发送者创建一个节点,并将通知的数据写入的该节点:通知的接受者则对该节点

ZooKeeper场景实践:(6)集群监控和Master选举

1. 集群机器监控 这通常用于那种对集群中机器状态,机器在线率有较高要求的场景,能够快速对集群中机器变化作出响应.这样的场景中,往往有一个监控系统,实时检测集群机器是否存活. 利用ZooKeeper有两个特性(读可监控,临时节点),就可以实现一种集群机器存活性监控系统: 1. 客户端在节点 x 上注册一个Watcher,那么如果x的子节点变化了,会通知该客户端 2. 创建EPHEMERAL类型的节点,一旦客户端和服务器的会话结束或过期,那么该节点就会消失 利用这两个特性,可以分别实现对客服端的状

为什么不使用ZooKeeper构建云平台发现服务?

本文作者通过ZooKeeper与Eureka作为 Service发现服务(注:WebServices 体系中的UDDI就是个发现服务)的优劣对比,分享了Knewton在云计算平台部署服务的经验.本文虽然略显偏激,但是看得出Knewton在云平台方面是非常有经验的,这篇文章从实践角度出发分别从云平台特点.CAP原理以及运维三个方面对比了ZooKeeper与Eureka两个系统作为发布服务的优劣,并提出了在云平台构建发现服务的方法论. 背景 很多公司选择使用 ZooKeeper作为Service发现

运动的云上新玩法:咕咚LBS场景实践

摘要:10月13日2016杭州云栖大会拉开帷幕,位置服务专场的CEO申波带来了"咕咚:位置服务,数据如何让运动更好玩有趣"的重要演讲.本次分享从咕咚的进化开始谈起,进而讲到社区+工具的运动核心点,重点介绍了LBS场景下精准的运动轨迹.社交以及O2O,最后分享了咕咚的线上新玩法.一起来欣赏吧--   以下内容根据演讲PPT及现场分享整理:  本文从咕咚的进化开始谈起,进而讲到社区+工具的运动核心点,重点介绍了LBS场景下精准的运动轨迹.社交以及O2O,最后分享了咕咚的线上新玩法. 以下为

Zookeeper(分布式应用程序协调服务)

1.简述 zookeeper,动物园管理者,动物饲养员.以下简称zk. 它是一个分布式一致性解决方案,为分布式应用提供分布式协调服务. 它开源.强大,得到了广泛的应用.Haddop,Storm都已经将zk作为核心组件,用于分布式协调. 2.集群角色 Leader,为客户端提供读写服务. Follower, 提供读服务,参与lerder选举. Observer,只提供读服务. 每个Server在工作过程中有三种状态: LOOKING:当前Server不知道leader是谁,正在搜寻: LEADIN

Python 装饰器学习以及实际使用场景实践

前言 前几天在看Flask框架,,不是非常的理解,回来补装饰器的功课.阅读很多的关于装饰器的文章,自己整理一下,适合自己的思路的方法和例子,与大家分享. app = Flask(__name__)  @app.route("/")  def hello():  return "Hello World!"  1.装饰器是什么 装饰器是Python语言中的高级语法.主要的功能是对一个函数.方法.或者类进行加工,作用是为已经存在的对象添加额外的功能,提升代码的可读性. 装