无法以编程方式上传数据到Zookeeper

Unable to upload data to Zookeeper programmatically

本文关键字:数据 Zookeeper 方式 编程      更新时间:2023-10-16

我已经在我的Ubuntu机器上安装了Zookeeper。我在集群模式下运行它,有三个z1, z2z3实例。当我用bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,...连接到它并执行ls /时,我看到一些列表,比如节点或数据(我不确定术语)。现在我想要的是用标准C++ client以编程方式上传一些数据。为了实现这一点,我有一堆函数,包括init,其中,我猜,开始一个会话,create函数,它内部调用zoo_acreate和一个空的(为了简单起见)回调函数create_complete

上面提到的最后两个函数是这样的:

void create(const char * path,
               const char * value) {
    zoo_acreate(zh, 
               path, 
               value, 
               0, 
               &ZOO_OPEN_ACL_UNSAFE, 
               0, 
               create_completion, 
               NULL); 
}
void create_completion (int rc, const char *value, const void *data) {
  // empty at this moment
}

然而,当我试图使用这些函数来上传一些数据到zookeeper时,我没有得到任何结果——实际上,没有错误,但同时没有数据。我使用这些函数的方式如下:

int main(){
    hostPort = (char *)("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183");
    init(hostPort); // as a result of invoking this function
    // I see in the console some logs, including this message:
    // Initiating client connection, host=127.0.0.1:2181,....
    create("/testworker", "");
    return 0; 
}

我认为,这段代码应该在Zookeeper中创建一个/testworker"文件夹",然而,它没有- ls /命令显示没有更改。我应该指出的一件有趣的事情是,似乎我的程序从未调用create_completion回调(我用cout检查了它)。所以,我可能需要一些特殊的标志和一些特殊的编译字符串为我的程序。我现在编译它的方式是:

$ g++ -o test test.cpp -I /...path_to_include_folder/ -L /..path_to_lib_folder/ -lzookeeper_mt

编辑

我稍微调查了一下这个问题,发现回调函数根本没有被调用。例如,启动会话的init函数不调用main_watcher callback。为什么呢?

编辑

我又调查了一下。事实证明,zookeeper_init(在我的init函数中调用)返回0作为errno的值,此外它还将zh(这是static zhandle_t *类型的zookeeper处理程序)设置为某些值,因此zh不是null,因此,根据文档,init函数应该是ok的(即使它不触发回调例程)。因此,很奇怪的是,我在控制台上没有错误消息,也没有得到标准zookeeper方法的错误标志,但回调和数据上传仍然不起作用。有什么问题,我怎么调试它?

编辑

这是我的一个小例子的完整源代码:

#include <iostream>
#include "proto.h"
#include "zookeeper.h"
#include "zookeeper_log.h"
#include "recordio.h"
#include "zookeeper.jute.h"
#include "zookeeper_version.h"
#include "errno.h"

using namespace std;
static char *hostPort;
static zhandle_t * zh;
static int connected = 0;
static int expired = 0;
static int server_id;
static struct String_vector * workers = NULL;
static struct String_vector * tasks = NULL;
void create(const char *, const char *);
void create_completion(int, const char *, const void *);
void main_watcher(zhandle_t *zkh,
      int type,
      int state,
      const char *path,
      void* context)
 {
   // cout << "HELLO FROM WATCHER " << endl; // Not printed when I remove comment. Why???
   if(type == ZOO_SESSION_EVENT){
    if(state == ZOO_CONNECTED_STATE){
      connected = 1;
    }
    else if(state == ZOO_AUTH_FAILED_STATE){
      connected = 0;
    }
    else if(state == ZOO_EXPIRED_SESSION_STATE){
      expired = 1;
      connected = 0;
      zookeeper_close(zkh);
    }
  }
}
int init(char* hostPort){
  srand(time(NULL));
  server_id = rand();
  zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);
  zh = zookeeper_init(hostPort, main_watcher, 15000, 0, 0, 0);
  return errno;
}
void create_completion(int rc, const char *value, const void * data){
  // empty at this moment for simplicity  
}
void create(const char * path, const char * value){
  zoo_acreate(zh, path, value, 0, &ZOO_OPEN_ACL_UNSAFE, 0,
      create_completion, NULL);
}

int main(){
 hostPort = (char *)("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183");
 init(hostPort);
 create("/testworkers", ""); // Do not see this "folder" /testworkers in Zookeeper. Why???
 return 0;
}

编辑

这真让我抓狂。我花了几天时间读了一本关于C++连接器到Zookeeper的书,没有结果,我刚刚拿了第一个Python连接器,花了不超过1.5分钟就完成了。但那不是我想要的。我想看看我怎么能做这个琐碎的事情在C++ -编译,连接和创建。仅此而已。

编辑

我用-DTHREADED选项编译了我的程序,但无济于事。尽管如此,zoo_acreate并没有创建任何东西。它不产生错误消息,不产生警告,不返回错误标志,也不提供任何结果。真奇怪的图书馆。

代码中有两个错误。

1。在这个字符串中,static int server_id;。必须为static clientid_t server_id;

2。init函数必须是

int init(char* hostPort)
{
      //srand(time(NULL));
      //server_id = rand();
      zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);
      zh = zookeeper_init(hostPort, main_watcher, 15000, &server_id, 0, 0);
      return errno;
 }

请注意zookeeper_init,函数srand(time(NULL));server_id = rand();必须被注释掉。

还有别的。参见main的新版本。我添加了无限循环

int main()
{
hostPort = (char *)("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183");
init(hostPort);
create("/testworkers", ""); // Do not see this "folder" /testworkers in Zookeeper. Why???
while(1)
{
     sleep(1);
}
return 0;
}

在创建ZNode时,您需要声明基本的ACL(访问控制列表)—下面是创建ZNode的一个基本示例:

    static zhandle_t *zh;
    static clientid_t myid;
    char buffer[512];    
    struct ACL CREATE_ONLY_ACL[] = {{ZOO_PERM_ALL, ZOO_ANYONE_ID_UNSAFE}};                                        
    struct ACL_vector CREATE_ONLY = {1, CREATE_ONLY_ACL};   

    zh = zookeeper_init("localhost:2181", watcher, 1000, 0, 0, 0);
    int rc = zoo_create(zh,"/xyz","value", 5, &CREATE_ONLY, ZOO_EPHEMERAL, buffer, sizeof(buffer)-1);             
    if (rc) {
       fprintf(stdout, "Error %d, %s for %s [%d] - could NOT create /xyz n", rc, zerror(rc), __FILE__, __LINE__);
    }
    else
       cout << "Created /xyc znode" << endl;
    // Watcher function -- basic handling                                                                        
    void watcher(zhandle_t *zzh, int type, int state, const char *path, void* context)                           
    {                                                                                                       
        fprintf(stdout, "Watcher %s state = %s", type2String(type), state2String(state));                        
        if (path && strlen(path) > 0) {                                                                          
            fprintf(stderr, " for path %s", path);                                                               
        }                                                                                                        
        fprintf(stdout, "n");                                                                                   
        if (type == ZOO_SESSION_EVENT) {                                                                         
            if (state == ZOO_CONNECTED_STATE) {                                                                  
                const clientid_t *id = zoo_client_id(zzh);                                                       
                if (myid.client_id == 0 || myid.client_id != id->client_id) {                                    
                    myid = *id;                                                                                  
                    fprintf(stdout, "Got a new session id: 0x%llxn", _LL_CAST_ myid.client_id);                 
                }                                                                                                
            } else if (state == ZOO_AUTH_FAILED_STATE) {                                                         
                fprintf(stdout, "Authentication failure. Shutting down...n");                                   
                zookeeper_close(zzh);                                                                            
                zh=0;                                                                                            
            } else if (state == ZOO_EXPIRED_SESSION_STATE) {                                                     
                fprintf(stdout, "Session expired. Shutting down...n");                                          
                zookeeper_close(zzh);                                                                            
                zh=0;                                                                                            
            }                                                                                                    
        }                                                                                                        
    }                                                                                                            

这将创建一个znode -然而它将在客户端关闭时消失,因为它具有ZOO_EPHEMERAL访问权限,如果您希望它在客户端断开连接后存在,那么您需要更改为不同的ACL