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

Unable to upload data to Zookeeper programmatically

我已经在我的 Ubuntu 机器上安装了 Zookeeper。我 运行 它处于集群模式,具有三个 z1z2z3 实例。当我使用 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 "folder",然而,它没有 - ls / 命令显示没有变化。我应该指出的一件有趣的事情是,我的程序似乎从未调用 create_completion 回调(我用 cout 检查过)。所以,我的程序可能需要一些特殊的标志和一些特殊的编译字符串。我现在编译的方式是:

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

编辑

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

编辑

我又研究了一下。事实证明,zookeeper_init(在我的 init 函数中调用)returns 0 作为 errno 的值,此外它设置 zh(这是 static zhandle_t * 类型的动物园管理员处理程序)到某个值,所以 zh 不是 null 等等,根据 documentationinit 函数应该没问题(即使它不会触发回调例程)。所以我在控制台中没有错误消息并且使用标准 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 并没有创造任何东西。它不会产生错误消息,不会产生警告,不会 return 错误标志,也不会提供任何结果。真奇怪的图书馆。

您的代码有两个错误。

1.In 这个字符串 static int server_id; 。必须是 static clientid_t server_id;

2.And 你的初始化函数必须是

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%llx\n", _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