ダウンロード
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);
}