この記事はスタンバイ Advent Calendar 2022の10日目の記事です。
昨日は@jsoizoさんのAWS JDBC Driver for MySQLのfailover機能に関する動作検証でした。
ClickHouse Keeper?
ClickHouseではレプリケーションや分散DDLの実行などの同期システムとして Zookeeper を使用しています。
ZookeeperはKafkaのバックグラウンドということもあり高速で安定しており信頼度も高いシステムです。しかし、ClickHouseの連携システムという点では構築や不具合時の運用に手間がかかっていました。そこで、去年リリースの21.4 から大替独自のClickHouse Keeperが組み込まれました。Zookeeperと採用するアルゴリズムや言語は異なりますが、同じインターフェースで作成されています。
ClickHouse Keeperが作られた経緯としては、Zookeeperがスナップショットの増加や障害時のリカバリなど運用が難しいため、という理由だったはず🤔 ただ、それ以上にclickhouse-serverに組み込まれていることから、別途同期用のサーバを立てることなくレプリケーションを行うことができるようになったことが強いと感じます。
この記事ではdockerを用いてローカル環境でZookeeper構成からClickHouse Keeperへの移行を試していきます。
Zookeeper構成で立ち上げる
docker-compose.yml
と必要な設定ファイル群を用意します。
clickhouse-serverを2コンテナ(clickhouse-server-1
、clickhouse-server-2
)、zookeeperを1コンテナの構成で構築します。
> tree .
.
├── docker-compose.yml
└── etc
└── clickhouse-server
└── config.d
├── clickhouse-server-1-macros.xml
├── clickhouse-server-2-macros.xml
└── zookeeper-config.xml
<?xml version="1.0"?>
<clickhouse>
<listen_host>0.0.0.0</listen_host>
<remote_servers>
<sample_cluster>
<shard>
<replica>
<host>clickhouse-server-1</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse-server-2</host>
<port>9000</port>
</replica>
</shard>
</sample_cluster>
</remote_servers>
<zookeeper>
<node>
<host>zookeeper</host>
<port>2181</port>
</node>
</zookeeper>
</clickhouse>
<?xml version="1.0"?>
<clickhouse>
<macros>
<cluster>sample_cluster</cluster>
<shard>0</shard>
<replica>0</replica>
</macros>
</clickhouse>
<?xml version="1.0"?>
<clickhouse>
<macros>
<cluster>sample_cluster</cluster>
<shard>0</shard>
<replica>1</replica>
</macros>
</clickhouse>
version: '3.7'
services:
clickhouse-server-1:
container_name: clickhouse-server-1
image: clickhouse/clickhouse-server:22.11
ports:
- "9000:9000"
- "8123:8123"
volumes:
- ./clickhouse-server-1-data:/var/lib/clickhouse
- ./etc/clickhouse-server/config.d/zookeeper-config.xml:/etc/clickhouse-server/config.d/zookeeper-config.xml
- ./etc/clickhouse-server/config.d/clickhouse-server-1-macros.xml:/etc/clickhouse-server/config.d/clickhouse-server-1-macros.xml
clickhouse-server-2:
container_name: clickhouse-server-2
image: clickhouse/clickhouse-server:22.11
ports:
- "9001:9000"
- "8124:8123"
volumes:
- ./clickhouse-server-2-data:/var/lib/clickhouse
- ./etc/clickhouse-server/config.d/zookeeper-config.xml:/etc/clickhouse-server/config.d/zookeeper-config.xml
- ./etc/clickhouse-server/config.d/clickhouse-server-2-macros.xml:/etc/clickhouse-server/config.d/clickhouse-server-2-macros.xml
zookeeper:
container_name: zookeeper
image: zookeeper
ports:
- "2181:2181"
volumes:
- ./volumes/tmp/zookeeper/data:/data
- ./volumes/tmp/zookeeper/datalog:/datalog
ファイルの作成が終わったら docker compose
で起動します。
> docker compose up -d
[+] Running 4/4
⠿ Network ac2022_default Created 0.1s
⠿ Container clickhouse-server-1 Started 0.6s
⠿ Container clickhouse-server-2 Started 0.6s
⠿ Container zookeeper Started 0.5s
立ち上がったらクライアントを用いてアクセスします。
> docker exec -it clickhouse-server-1 clickhouse-client
ClickHouse client version 22.11.1.1360 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 22.11.1 revision 54460.
ce8ce5ce80a5 :)
system.zookeeper
への検索が行えることでZookeeperとの連携ができていることが確認できます。
ce8ce5ce80a5 :) SELECT * FROM system.zookeeper WHERE path IN ('/', '/clickhouse')
┌─name───────┬─value─┬─path────────┐
│ zookeeper │ │ / │
│ clickhouse │ │ / │
│ task_queue │ │ /clickhouse │
└────────────┴───────┴─────────────┘
3 rows in set. Elapsed: 0.006 sec.
連携が確認できたら、動作確認用のレプリケーションテーブルの作成を行っていきます。
ce8ce5ce80a5 :) CREATE TABLE sample ON CLUSTER '{cluster}' (id Int, val String) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/sample', '{replica}') ORDER BY id
┌─host────────────────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ clickhouse-server-2 │ 9000 │ 0 │ │ 1 │ 0 │
│ clickhouse-server-1 │ 9000 │ 0 │ │ 0 │ 0 │
└─────────────────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
2 rows in set. Elapsed: 0.120 sec.
ce8ce5ce80a5 :) INSERT INTO sample VALUES (1, 'abc'), (2, 'bcd')
Ok.
2 rows in set. Elapsed: 0.031 sec.
ce8ce5ce80a5 :) SELECT * FROM sample
┌─id─┬─val─┐
│ 1 │ abc │
│ 2 │ bcd │
└────┴─────┘
2 rows in set. Elapsed: 0.005 sec.
clickhouse-server-2
でもテーブルが作成されデータが同期されていることを確認します。
> docker exec -it clickhouse-server-2 clickhouse-client
ClickHouse client version 22.11.1.1360 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 22.11.1 revision 54460.
9333fd4d6715 :) SELECT * FROM sample
SELECT *
FROM sample
Query id: 57808e49-35c3-436e-8b57-ce15a4f3df68
┌─id─┬─val─┐
│ 1 │ abc │
│ 2 │ bcd │
└────┴─────┘
2 rows in set. Elapsed: 0.006 sec.
Zookeeperにパスが作成されていることも確認します。
9333fd4d6715 :) SELECT * FROM system.zookeeper WHERE path = '/clickhouse/tables/0'
┌─name───┬─value─┬─path─────────────────┐
│ sample │ │ /clickhouse/tables/0 │
└────────┴───────┴──────────────────────┘
1 row in set. Elapsed: 0.002 sec.
ここまででZookeeperの構成でレプリケーションテーブルを作成、データの登録まで行いました。これからZookeeperのデータをclickhouse-keeperへ移行、コンテナの構成もclickhouse-keeperへ切り替えます。
Zookeeper -> Clickhouse Keeperへのデータ移行
マイグレーションについてはドキュメントがあります。専用のツール(clickhouse-keeper-converter
)も用意されており、ZooKeeperのバージョンが 3.4
以上の場合これが使用できます。ツールはclickhouse-serverのイメージに入っています。
今回はドキュメントに従った移行を見ていきます。
まずはZookeeperを停止し、スナップショットとデータログをclickhouse-serverに移動します。docker compose
で行うには volumes
を駆使していきます。
> docker compose down
[+] Running 2/2
⠿ Container zookeeper Removed 10.2s
⠿ Container clickhouse-server-2 Removed 10.2s
⠿ Container clickhouse-server-1 Removed 10.3s
⠿ Network ac2022_default Removed 0.1s
今回、必要なZookeeperのデータはvolumes/tmp
に入るようにしています。なぜかclickhouse-keeper
のイメージには clickhouse-keeper-converter
が入っていないので、ここではclickhouse-server-1
にデータを移して変換を行います。
docker-compose.yml
を次のように変更し、dockerを立ち上げます。
version: '3.7'
services:
clickhouse-server-1:
container_name: clickhouse-server-1
image: clickhouse/clickhouse-server:22.11
ports:
- "9000:9000"
- "8123:8123"
volumes:
- ./volumes/tmp:/tmp # Zookeeperのデータをマウントする
- ./clickhouse-server-1-data:/var/lib/clickhouse
- ./etc/clickhouse-server/config.d/zookeeper-config.xml:/etc/clickhouse-server/config.d/zookeeper-config.xml
- ./etc/clickhouse-server/config.d/clickhouse-server-1-macros.xml:/etc/clickhouse-server/config.d/clickhouse-server-1-macros.xml
> docker compose up -d
[+] Running 3/3
⠿ Network ac2022_default Created 0.0s
⠿ Container clickhouse-server-1 Started 0.5s
立ち上がったらclickhouse-server-1
にbash
で入り、clickhouse-keeper-converter
を実行します。
> docker exec -it clickhouse-server-1 bash
bash-5.1# clickhouse-keeper-converter --zookeeper-logs-dir /tmp/zookeeper/datalog/version-2 --zookeeper-snapshots-dir /tmp/zookeeper/data/version-2 --output-dir /tmp/keeper/snapshots
Totally have 1 snapshots, will use latest
Deserializing storage snapshot /tmp/zookeeper/data/version-2/snapshot.0
Magic deserialized, looks OK
Sessions and timeouts deserialized
ACLs deserialized
Deserializing data from snapshot
Finished, snapshot ZXID 0
Totally have 1 logs
Deserializing log /tmp/zookeeper/datalog/version-2/log.1
Header looks OK
Finished /tmp/zookeeper/datalog/version-2/log.1 deserialization, totally read 112 records
Snapshot serialized to path:/tmp/keeper/snapshots/snapshot_13.bin.zstd
成功すると変更後のファイルが出力されます。今回は最終行にある(/tmp/keeper/snapshots/snapshot_13.bin.zstd
)が成果物になります。
変換が終わったらサーバを落としてください。
> docker compose down
[+] Running 2/2
⠿ Container clickhouse-server-1 Removed 10.3s
⠿ Network ac2022_default Removed 0.1s
変換したスナップショットファイルはclickhouse-keeperのスナップショット用のディレクトリに移す必要があります。ここでは以下の通りローカルにマウント用のディレクトリを作成し、変換後のファイルを移動します。
> mkdir -p volumes/var/lib/clickhouse/coordination/snapshots
> cp volumes/tmp/keeper/snapshots/* volumes/var/lib/clickhouse/coordination/snapshots/.
Clickhouse Keeperの立ち上げ
Zookeeperのデータの変換も終わり、clickhouse-keeperを用いた構成を構築していきます。まずは必要なファイルを作成します。
> tree .
.
├── docker-compose.yml
├── etc
│ ├── clickhouse-keeper
│ │ └── keeper_config.xml # <-- このファイルを追加
│ └── clickhouse-server
│ └── config.d
│ ├── clickhouse-keeper-config.xml # <-- このファイルを追加
│ ├── clickhouse-server-1-macros.xml
│ └── clickhouse-server-2-macros.xml
└── volumes
keeper_config.xml
はデフォルトのファイルに <listen_host>0.0.0.0</listen_host>
を追加しています。clickhouse-serverみたいにconfigの項目で上書きができれば良かったのですが、見た感じできなそうなのでサーバから持ってきたファイルを変更し、ファイルごと上書きます。
設定ファイルを見るとスナップショットのパスなどの設定があるので、先ほど変換したファイルはこのパスにマウントします。
<?xml version="1.0"?>
<clickhouse>
<listen_host>0.0.0.0</listen_host> <!-- この行を追加 -->
<logger>
<!-- Possible levels [1]:
- none (turns off logging)
- fatal
- critical
- error
- warning
- notice
- information
- debug
- trace
[1]: https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105-L114
-->
<level>trace</level>
<log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
<errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
<!-- Rotation policy
See https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/FileChannel.h#L54-L85
-->
<size>1000M</size>
<count>10</count>
<!-- <console>1</console> --> <!-- Default behavior is autodetection (log to console if not daemon mode and is tty) -->
</logger>
<max_connections>4096</max_connections>
<keeper_server>
<tcp_port>9181</tcp_port>
<!-- Must be unique among all keeper serves -->
<server_id>1</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/logs</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<min_session_timeout_ms>10000</min_session_timeout_ms>
<session_timeout_ms>100000</session_timeout_ms>
<raft_logs_level>information</raft_logs_level>
<!-- All settings listed in https://github.com/ClickHouse/ClickHouse/blob/master/src/Coordination/CoordinationSettings.h -->
</coordination_settings>
<!-- enable sanity hostname checks for cluster configuration (e.g. if localhost is used with remote endpoints) -->
<hostname_checks_enabled>true</hostname_checks_enabled>
<raft_configuration>
<server>
<id>1</id>
<!-- Internal port and hostname -->
<hostname>localhost</hostname>
<port>9234</port>
</server>
<!-- Add more servers here -->
</raft_configuration>
</keeper_server>
<openSSL>
<server>
<!-- Used for secure tcp port -->
<!-- openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt -->
<certificateFile>/etc/clickhouse-keeper/server.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-keeper/server.key</privateKeyFile>
<!-- dhparams are optional. You can delete the <dhParamsFile> element.
To generate dhparams, use the following command:
openssl dhparam -out /etc/clickhouse-keeper/dhparam.pem 4096
Only file format with BEGIN DH PARAMETERS is supported.
-->
<dhParamsFile>/etc/clickhouse-keeper/dhparam.pem</dhParamsFile>
<verificationMode>none</verificationMode>
<loadDefaultCAFile>true</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
</openSSL>
</clickhouse>
clickhouse-server側の設定はzookeeperの設定をclickhouse-keeperに置き換えるだけです。
<?xml version="1.0"?>
<clickhouse>
<listen_host>0.0.0.0</listen_host>
<remote_servers>
<sample_cluster>
<shard>
<replica>
<host>clickhouse-server-1</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse-server-2</host>
<port>9000</port>
</replica>
</shard>
</sample_cluster>
</remote_servers>
<zookeeper>
<node>
<host>clickhouse-keeper</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
最後にdocker-compose.ymlです。zookeeperの定義を削除し、clickhouse-keeperの定義を追加します。clickhouse-serverにマウントする設定ファイルもClickHouse Keeperのものに変更します。変換に使用したマウントは削除します。
version: '3.7'
services:
clickhouse-server-1:
container_name: clickhouse-server-1
image: clickhouse/clickhouse-server:22.11
ports:
- "9000:9000"
- "8123:8123"
volumes:
- ./volumes/clickhouse-server-1-data:/var/lib/clickhouse
- ./etc/clickhouse-server/config.d/clickhouse-keeper-config.xml:/etc/clickhouse-server/config.d/clickhouse-keeper-config.xml
- ./etc/clickhouse-server/config.d/clickhouse-server-1-macros.xml:/etc/clickhouse-server/config.d/clickhouse-server-1-macros.xml
clickhouse-server-2:
container_name: clickhouse-server-2
image: clickhouse/clickhouse-server:22.11
ports:
- "9001:9000"
- "8124:8123"
volumes:
- ./volumes/clickhouse-server-2-data:/var/lib/clickhouse
- ./etc/clickhouse-server/config.d/clickhouse-keeper-config.xml:/etc/clickhouse-server/config.d/clickhouse-keeper-config.xml
- ./etc/clickhouse-server/config.d/clickhouse-server-2-macros.xml:/etc/clickhouse-server/config.d/clickhouse-server-2-macros.xml
clickhouse-keeper:
container_name: clickhouse-keeper
image: clickhouse/clickhouse-keeper:22-alpine
ports:
- "9181:9181"
volumes:
- ./volumes/var/lib/clickhouse/coordination/snapshots:/var/lib/clickhouse/coordination/snapshots
- ./etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
ファイルを作成したらdockerを起動して確認します。
> docker compose up -d
[+] Running 4/4
⠿ Container clickhouse-keeper Started 0.4s
⠿ Container clickhouse-server-2 Running 0.0s
⠿ Container clickhouse-server-1 Running 0.0s
clickhouse-server-1
から確認します。
> docker exec -it clickhouse-server-1 clickhouse-client
ClickHouse client version 22.11.1.1360 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 22.11.1 revision 54460.
Zookeeperのスナップショットの移行が行われていることを確認します。
84483aff7bbe :) SELECT * FROM system.zookeeper WHERE path = '/clickhouse/tables/0'
┌─name───┬─value─┬─path─────────────────┐
│ sample │ │ /clickhouse/tables/0 │
└────────┴───────┴──────────────────────┘
1 row in set. Elapsed: 0.003 sec.
パスが存在することを確認できました。
続いてテーブルの検索と、データを追加してレプリケーションが働くことを確認します。
84483aff7bbe :) SELECT * FROM sample
┌─id─┬─val─┐
│ 1 │ abc │
│ 2 │ bcd │
└────┴─────┘
2 rows in set. Elapsed: 0.003 sec.
84483aff7bbe :) INSERT INTO sample VALUES (3, 'cdf')
Ok.
1 row in set. Elapsed: 0.031 sec.
84483aff7bbe :) SELECT * FROM sample
┌─id─┬─val─┐
│ 1 │ abc │
│ 2 │ bcd │
└────┴─────┘
┌─id─┬─val─┐
│ 3 │ cdf │
└────┴─────┘
3 rows in set. Elapsed: 0.006 sec.
clickhouse-server-2
からレプリケーションを確認します。
$ docker exec -it clickhouse-server-2 clickhouse-client
ClickHouse client version 22.11.1.1360 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 22.11.1 revision 54460.
c41d6e631408 :) SELECT * FROM sample
┌─id─┬─val─┐
│ 1 │ abc │
│ 2 │ bcd │
└────┴─────┘
┌─id─┬─val─┐
│ 3 │ cdf │
└────┴─────┘
3 rows in set. Elapsed: 0.006 sec.
さいごに
ZookeeperからClickHouse Keeperへの移行を行いました。サーバの停止が必要とはなりますが専用のツールも用意されていて(データ量が多い場合などいくつか考慮することはありそうですが、)それなりに簡単に移行できました。
ClickHouseのホスティングサービスClickHouse CloudやAltinity.Cloudもできたことから今後も運用が容易になるような機能やツールが追加されていくような気がしています。
今回作成したファイルは以下にあります
Dockerを利用して試すのは気軽にできていいのですが、データや設定ファイルなど考慮することが多く面倒でした。あと、記事にするとごちゃっとなりますね😅