ZooKeeper 3.8.4 の導入と C API のビルド手順

ダウンロード

wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4.tar.gz
tar -zxvf apache-zookeeper-3.8.4.tar.gz
cd apache-zookeeper-3.8.4

直接使用

cd conf
cp zoo_sample.cfg zoo.cfg # サンプル設定ファイルをコピーして使用
cd ../bin/
./zkServer.sh start # サーバーを起動
./zkServer.sh status # サーバーの状態を確認

C API のコンパイル

依存関係のインストール

sudo apt update
sudo apt-get install libssl-dev ant libcppunit-dev maven openjdk-17-jdk

JDK 環境変数の設定

echo "export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which javac))))" >> ~/.bashrc
source ~/.bashrc

Maven ミラーの設定

# ユーザーレベルの設定ファイルを作成
mkdir -p ~/.m2
cp /usr/share/maven/conf/settings.xml ~/.m2/
vim ~/.m2/settings.xml  # 設定を編集

<mirrors>
	<mirror>
	  <id>aliyun</id>
	  <mirrorOf>central</mirrorOf>
	  <name>Aliyun Maven Mirror</name>
	  <url>https://maven.aliyun.com/repository/public</url>
	</mirror>
</mirrors>
echo $JAVA_HOME  # JDK のパスが表示されることを確認
which javadoc    # 必要なツールが存在することを確認

コンパイルの実行

# apache-zookeeper-3.8.4/ ディレクトリで実行
mvn install -Pfull-build -DskipTests # README_packaging.md を参照

コンパイル後のファイルのパス

コンパイルされた C クライアントは以下の場所にあります:
- `zookeeper-client/zookeeper-client-c/target/c/bin`                 - ユーザー実行ファイル
- `zookeeper-client/zookeeper-client-c/target/c/lib`                 - ネイティブライブラリ
- `zookeeper-client/zookeeper-client-c/target/c/include/zookeeper`   - ネイティブライブラリのヘッダー

システムパスへのインストール

# apache-zookeeper-3.8.4/ ディレクトリで実行
sudo cp -r zookeeper-client/zookeeper-client-c/target/c/lib/* /usr/local/lib/ # ライブラリ
sudo cp -r zookeeper-client/zookeeper-client-c/target/c/include/zookeeper /usr/local/include/ # ヘッダー
sudo cp zookeeper-client/zookeeper-client-c/target/c/bin/* /usr/local/bin/ # 実行ファイル

参考

https://www.cnblogs.com/xinyonghu/p/11031729.html
https://blog.csdn.net/qq_18402475/article/details/135623697

error while loading shared libraries: libzookeeper_mt.so.2: cannot open shared object file: No such file or directory

動的ライブラリキャッシュの更新

ldconfig 

C++ API プログラミング例

多くの古い同期メソッドは非推奨となっており、ここでは非同期メソッドを使用します。

#include "zookeeperutil.h"
#include "mprpcapplication.h"
#include <cstring>
#include <iostream>
#include <semaphore.h>
#include <string>
#include <zookeeper/zookeeper.h>

// タイムアウト時間を生成(デフォルト10秒)
void generateTimeoutTimeSpec(struct timespec &ts, int timeout_sec = 10)
{
    struct timespec now;
    clock_gettime(CLOCK_REALTIME, &now);
    ts.tv_sec = now.tv_sec + timeout_sec;
    ts.tv_nsec = now.tv_nsec;
}

// グローバルウォッチャーハンドラ
void globalWatcherHandler(zhandle_t *zh, int type, int state, const char *path, void *watcherCtx)
{
    if (type == ZOO_SESSION_EVENT && state == ZOO_CONNECTED_STATE)
    {
        std::cout << "ZooKeeper への接続に成功しました" << std::endl;
        semaphore_t *syncSem = (semaphore_t *)zoo_get_context(zh);
        sem_post(syncSem);
    }
}

ZooKeeperClient::ZooKeeperClient() : m_zhandle(nullptr)
{
    // 必要に応じてログレベルを設定
    // zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
}

ZooKeeperClient::~ZooKeeperClient()
{
    if (m_zhandle != nullptr)
    {
        zookeeper_close(m_zhandle);
    }
}

void ZooKeeperClient::Start()
{
    std::string host = MpRpcApplication::GetInstance().GetConfig().Load("zookeeperip");
    std::string port = MpRpcApplication::GetInstance().GetConfig().Load("zookeeperport");
    std::string connectionString = host + ":" + port;

    m_zhandle = zookeeper_init(connectionString.c_str(), globalWatcherHandler, 30000, 0, nullptr, 0);
    if (m_zhandle == nullptr)
    {
        std::cerr << "ZooKeeper 初期化に失敗しました" << std::endl;
        exit(EXIT_FAILURE);
    }

    semaphore_t syncSem;
    sem_init(&syncSem, 0, 0);
    zoo_set_context(m_zhandle, &syncSem);

    struct timespec ts;
    generateTimeoutTimeSpec(ts);
    if (sem_timedwait(&syncSem, &ts) != 0)
    {
        std::cerr << "ZooKeeper 接続タイムアウト" << std::endl;
        sem_destroy(&syncSem);
        exit(EXIT_FAILURE);
    }

    sem_destroy(&syncSem);
    std::cout << "ZooKeeper 初期化成功" << std::endl;
}

void ZooKeeperClient::Create(const char *path, const char *data, int dataLength, int state)
{
    struct AsyncCallbackContext
    {
        int returnCode; // 非同期スレッドの戻り値
        semaphore_t syncSem; // 非同期スレッドの同期用セマフォ
    } existsContext, createContext;

    sem_init(&existsContext.syncSem, 0, 0);
    existsContext.returnCode = ZSYSTEMERROR;

    zoo_aexists(m_zhandle, path, 0,
                [](int rc, const struct Stat *, const void *data) {
                    auto *ctx = (AsyncCallbackContext *)data;
                    ctx->returnCode = rc;
                    sem_post(&ctx->syncSem);
                },
                &existsContext);

    struct timespec ts;
    generateTimeoutTimeSpec(ts);
    if (sem_timedwait(&existsContext.syncSem, &ts) != 0)
    {
        std::cerr << "zoo_aexists タイムアウト: " << path << std::endl;
        sem_destroy(&existsContext.syncSem);
        return;
    }
    sem_destroy(&existsContext.syncSem);

    if (existsContext.returnCode == ZNONODE)
    {
        // ノードを作成
        sem_init(&createContext.syncSem, 0, 0);
        createContext.returnCode = ZSYSTEMERROR;

        zoo_acreate(m_zhandle, path, data, dataLength, &ZOO_OPEN_ACL_UNSAFE, state,
                    [](int rc, const char *value, const void *data) {
                        auto *ctx = (AsyncCallbackContext *)data;
                        ctx->returnCode = rc;
                        sem_post(&ctx->syncSem);
                    },
                    &createContext);

        generateTimeoutTimeSpec(ts);
        if (sem_timedwait(&createContext.syncSem, &ts) != 0)
        {
            std::cerr << "zoo_acreate タイムアウト: " << path << std::endl;
            sem_destroy(&createContext.syncSem);
            return;
        }

        sem_destroy(&createContext.syncSem);

        if (createContext.returnCode == ZOK)
        {
            std::cout << "znode 作成成功: " << path << std::endl;
        }
        else
        {
            std::cerr << "znode 作成失敗: " << path << ", エラー: " << createContext.returnCode << std::endl;
            exit(EXIT_FAILURE);
        }
    }
    else if (existsContext.returnCode == ZOK)
    {
        std::cout << "znode は既に存在します: " << path << std::endl;
        std::string value = GetData(path);
        std::cout << "データ: " << value << std::endl;
    }
    else
    {
        std::cerr << "zoo_aexists 失敗: " << path << ", エラー: " << existsContext.returnCode << std::endl;
    }
}

std::string ZooKeeperClient::GetData(const char *path)
{
    struct DataFetchContext
    {
        char *buffer;
        int returnCode;
        semaphore_t syncSem;
    };

    char buf[64] = {0};
    DataFetchContext ctx{buf, ZSYSTEMERROR};
    sem_init(&ctx.syncSem, 0, 0);

    zoo_aget(m_zhandle, path, 0,
             [](int rc, const char *value, int value_len,
                const struct Stat *, const void *data) {
                 auto *ctx = (DataFetchContext *)data;
                 ctx->returnCode = rc;
                 if (rc == ZOK && value != nullptr)
                 {
                     int len = (value_len < 63) ? value_len : 63;
                     memcpy(ctx->buffer, value, len);
                     ctx->buffer[len] = '\0';
                 }
                 sem_post(&ctx->syncSem);
             },
             &ctx);

    struct timespec ts;
    generateTimeoutTimeSpec(ts);
    if (sem_timedwait(&ctx.syncSem, &ts) != 0)
    {
        std::cerr << "znode データ取得タイムアウト: " << path << std::endl;
        sem_destroy(&ctx.syncSem);
        return "";
    }

    sem_destroy(&ctx.syncSem);

    if (ctx.returnCode != ZOK)
    {
        std::cerr << "znode データ取得エラー: " << path << ", rc=" << ctx.returnCode << std::endl;
        return "";
    }

    return std::string(buf);
}

タグ: ZooKeeper C++ Maven JDK linux

7月20日 01:48 投稿