0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ClickHouse Managed Postgres の HA(standby) を解説しつつ、同期 standby のトレードオフをコミットレイテンシで実測してみた

0
Posted at

1. はじめに

ClickHouse(以下 CH)が 2026 年に公開ベータとして出した Postgres managed by ClickHouse(以下 Managed Postgres)には、最大 2 台の standby を持つ HA があります。その仕様を読むと、台数によってレプリケーションの方式が切り替わると書かれています。

With two standbys ... the primary waits for acknowledgement from at least one standby before confirming writes ...
With one standby ... writes commit to the primary without waiting for acknowledgement from the standby. ... high availability doesn't slow down your writes due to additional network latency.
High availability | ClickHouse Docs

つまり「2 台=同期(少なくとも 1 台の確認を待つ)/ 1 台=非同期(待たない)」で、非同期側はわざわざ "doesn't slow down your writes due to additional network latency" と書いてあります。では、その 「同期にしたときに乗る追加のネットワーク遅延」は実際に何ミリ秒なのか。本記事は、この HA Docs の仕組みを解説したうえで、同期 standby のトレードオフをコミットレイテンシとして実測します。

なお、手動フェイルオーバーを発動する手段は本記事執筆時点(2026 年 6 月・ベータ)のコンソール・Docs では確認できませんでした。フェイルオーバーそのものの挙動検証はできないため、本記事は 「standby を積むと書き込みがどれだけ重くなるか」 に絞ります。

1.1. 今回の検証ゴール

# 検証項目 確認できれば OK の条件
1 standby 0/1/2 のレプリケーション構成(同期/非同期/quorum)を実機で確認し、HA Docs の HA モデルを裏付ける 各構成で synchronous_standby_names / pg_stat_replication を採取し、2=quorum・1=async・0=なし を示せる
2 同期(2) と非同期(1) のコミットレイテンシ差を実測し、Docs の "additional network latency" を ms 化する 単発 UPDATE のレイテンシを構成間で比較し、差を分離できる
3 同期で並列数を上げたときの TPS への影響もあわせて確認する -c64 / -c128 の TPS を構成間の相対比で示せる

1.2. 結論(先出し)

  • 同期 standby(2 台・quorum)のトレードオフは、1 コミットあたり約 +1.0〜1.3 msでした(非同期 1 台との差)。これが Docs の言う "additional network latency" の実体とみられます
  • 読み取りのレイテンシは構成(0/1/2)でほぼ不変(3.85〜3.95 ms、差 ±0.1 ms 以内)。Docs どおり「standby は読み取りの経路に入らない」ことの裏返しです
  • 非同期(1 台)は無し(0 台)とコミットレイテンシがほぼ同じでした。「非同期は書き込みを遅くしない」が実測でも成り立ちます
  • 並列数を上げたときの TPS は同期で -c64 で約 -11%、-c128 で約 -16%(非同期比)。ただし今回の Managed Postgres は 2 vCPU でサーバ CPU が約 70% まで上がっており、この低下は同期 ACK だけでなくサーバ CPU の頭打ちも混じります(5 章で注記)
  • 実装は AWS の上に「素の PostgreSQL のストリーミングレプリケーション + quorum 同期(synchronous_standby_names = ANY 1 (...))」を載せた論理的な仕組みでした。AWS RDS のマネージド Multi-AZ とは作りが異なるとみられます(2 章)

2. Managed Postgres の HA モデル

2.1. standby の台数とレプリケーション方式

HA Docs によると、standby はプロビジョニング時、または後から Settings で 0〜2 台に調整できます。

standby 台数 レプリケーション方式 コミット確定の条件
0 なし ローカルの WAL flush のみ
1 非同期(asynchronous) standby の確認を待たずにコミット
2 同期(synchronous, quorum) 2 台のうち少なくとも 1 台の確認を待ってコミット

ポイントは 2 台で初めて同期になることと、その同期が quorum(ANY 1) である点です。これは後述のとおり、実機の設定値から確認できました(4 章)。

2.2. 実装は「素の PostgreSQL ストリーミングレプリ + quorum 同期」

実機の設定値を見ると、これは PostgreSQL ネイティブの仕組みそのものでした(詳細な値は 4 章)。

  • 2 台構成では synchronous_standby_names = ANY 1 (standby1, standby2)synchronous_commit = on。つまり PostgreSQL の quorum コミット(PostgreSQL 10 以降の標準機能)で「どちらか 1 台」の WAL flush 確認を待つ
  • pg_stat_replication に walreceiver が並び、state = streaming。物理ストリーミングレプリケーションそのもの

公式ブログ Postgres managed by ClickHouse によれば、基盤は Ubicloud(ローカル NVMe を備えた VM を提供するオープンソースのクラウド基盤)の NVMe Postgres で、ClickHouse Cloud 傘下の AWS アカウント内で動き、バックアップは WAL-G(PostgreSQL 向けのバックアップ/リストアツール)です。要するに AWS の計算資源の上に、素の PostgreSQL の同期レプリ設定で HA を組んだ「論理的な仕組み」 であり、AWS のストレージ層レプリケーションや RDS のマネージド機構ではありません。

2.3. なぜ「1 台=非同期 / 2 台=同期」なのか

Docs は方式(what)を書きますが、理由(why)は明記していません。これは PostgreSQL 運用の一般的な考え方で説明できます。

  • 単独の同期 standby は危険です。synchronous_standby_names に 1 台だけ指定して synchronous_commit = on にすると、その standby が落ちたとき primary は来ない確認を待ち続け、全コミットがブロックします
  • だから 1 台のときは非同期にして、書き込みを止めないようにする(フェイルオーバー時に直近の数トランザクションを失うリスクだけを負う)
  • 2 台+ quorum(ANY 1) にすると、どちらか 1 台の確認で済むため、1 台落ちても残り 1 台が quorum を満たして書き込みが止まりません。同期の耐久性(最低 1 つの遠隔確定コピー)を保ちつつ、単一障害で詰まらない構成になります

FIRST 1 ではなく ANY 1(速い方・生きている方が満たせばよい)を選んでいるのも、可用性を優先した設計と考えられます。

2.4. AWS RDS Multi-AZ クラスター との違い

「2 台のスタンバイで、少なくとも 1 台の確認でコミット」という発想は、AWS の RDS Multi-AZ DB クラスター(準同期・1 ライター+2 リーダー)とよく似ています。ただし実装と運用面では違いがあります。

観点 CH Managed Postgres(2 standby) RDS Multi-AZ DB クラスター
レプリ方式 PostgreSQL ネイティブ ストリーミング+quorum 同期 AWS の準同期(semisynchronous)
コミット確定 2 台中 ANY 1 が WAL flush を確認 2 リーダー中、少なくとも 1 台が確認
セカンダリで読み取り 不可(HA 専用) 可(読み取りスケールに使える)
設定の可視性 pg_stat_replication 等で見える(素の PostgreSQL) AWS 管理で不可視
基盤 Ubicloud の NVMe Postgres(CH の AWS 内) RDS マネージド

一番の違いは、RDS はリーダーを読み取りに使えるのに対し、CH の standby は読み取りに公開されない点です(Docs 明記。WAL replay と読み取りが競合してフェイルオーバーの準備を遅らせるため)。CH での読み取りスケールは別途 read replica を使う整理になります。

AWS の HA 方式ごとの書き込みトレードオフも並べておくと、CH の位置づけがはっきりします。

  • Multi-AZ DB インスタンス(standby 1 台): ストレージ層の同期レプリ。書き込みは別 AZ の standby ストレージ確定を待つため latency が増え、standby は読み取りに使えません
  • Multi-AZ DB クラスター(reader 2 台): WAL だけを準同期で 2 台へ並列送信し、少なくとも 1 台の ACK でコミット(ローカル NVMe を活用)。AWS は Multi-AZ インスタンス比で「最大 2 倍速いコミットレイテンシ」と主張し、reader は読み取りに使えます

つまり CH Managed Postgres の 2 standby は、この Multi-AZ DB クラスターと発想がほぼ同じと思われます(WAL のみ・少なくとも 1 台の ACK・ローカル NVMe)。ただし RDS 側の内部実装は非公開のため、ここは公開情報からの推測です。確認できる違いは「standby を読み取りに出すか(CH は出さない)」と「設定が PostgreSQL ネイティブで見えるか」です。本記事で実測した同期の +1.0〜1.3 ms/commit は、この種の クロス AZ 準同期に共通して乗るコストとみられます。

ちなみに AWS が公表しているのは「Multi-AZ インスタンス比で最大 2 倍速いコミット」という相対値と、HammerDB(TPC-C) による NOPM ベンチ(Single-AZ / Multi-AZ instance / Multi-AZ cluster の比較。cluster は Single-AZ とほぼ同等、instance が最も低い)までで、「HA で書き込みに何 ms 乗るか」という絶対値は公開していません。HA の書き込みコストは構成・ワークロード依存なので、結局は自分の構成で測るしかありません。本記事の +1.0〜1.3 ms は、その「CH 版を実測した 1 つの具体値」という位置づけです。


3. 検証構成

3.1. 計測対象とクライアント

項目
サービス ClickHouse Managed Postgres (beta)
インスタンス r6gd.large / 2 vCPU / 16 GiB RAM / NVMe(Memory optimized・ARM)
リージョン Tokyo (ap-northeast-1)
PostgreSQL 18.4 (Ubuntu 18.4-1.pgdg22.04+1, aarch64)
データ規模 pgbench SF=200 → DB 約 3 GB(< 16 GiB RAM、メモリ内に収まる)
クライアント EC2 m8g.2xlarge(8 vCPU / 32 GiB / Graviton4)/ Amazon Linux 2023 / pgbench 18.3
接続 公開エンドポイント / NAT GW 経由 / sslmode=require

service_summary.png
3-1: サービス概要(Tokyo・r6gd.large・2 vCPU・16 GB・2 standbys・Version 18)

3.2. 計測手法(同期 ACK を分離する)

同期 standby のトレードオフは「コミットごとに standby の確認を待つ往復」です。これを埋もれさせないために、ワークロードを工夫しました。

  • 主指標は単発 autocommit UPDATEUPDATE pgbench_accounts ... WHERE aid = :aid)。1 往復+コミットだけなので、コミットの待ちが相対的に大きく出ます
  • 読み取り(pgbench -S)をベースラインに置き、(UPDATE − S) でコミット由来のコストを分離します。クライアントからサーバまでの往復は読み書き共通なので、構成間で比べれば打ち消せます
  • データはメモリ内(約 3 GB < 16 GiB)に収め、ストレージ I/O が混じらないようにしました
  • 各計測は 3 回の平均。クライアントは全構成で同一の EC2 を使い回しています

なお標準の TPC-B 風(pgbench の通常トランザクション)は BEGIN / UPDATE / SELECT / INSERT / COMMIT と往復が多く、約 1 ms の同期差がばらつきに埋もれてしまうため、本記事では参考扱いです。

PrivateLink(VPC 内プライベート接続)は Managed Postgres ではサポートチケット経由で、コンソールからのセルフサービス追加はできませんでした。そのため公開エンドポイント+NAT GW 経由で接続しています。同期コストは構成間の差で見るため、公開エンドポイントの往復遅延は結論に影響しないと考えています


4. 構成の裏取り(HA モデルの実機確認)

コンソールで Standby を 0 → 1 → 2 と切り替え、それぞれで設定値を採取しました。

構成 コンソール synchronous_standby_names pg_stat_replication synchronous_commit
cfg0 Standby = 0 (空) 0 行 on
cfg1 Standby = 1 (空) 1 行・sync_state = asyncstate = streaming on
cfg2 Standby = 2 ANY 1 (pvbxxxx, pveyyyy) 2 行・両方 sync_state = quorumstate = streaming on

cfg2 の 2 台は sync_priority が同値で、4 種類の lag バイト(sent/write/flush/replay)はすべて 0 でした。ANY 1 の対称性(どちらも quorum を満たせる)が確認できます。

また pg_stat_replication の内部アドレスから、primary と 2 台の standby はそれぞれ異なる AZ(別サブネット)に配置されていることも確認できました。HA Docs の "across different availability zones" と整合し、後述のクロス AZ 往復(6.1 章)の前提になります。

standby0_scaling.png standby1_service_actions-2.png standby2_scaling-2.png
4-1: Standby = 0 4-2: Standby = 1 4-3: Standby = 2

これは HA Docs の「0=なし / 1=非同期 / 2=同期(少なくとも 1 台の確認)」と完全に一致します。

4.1. 切替時に観測した挙動

  • standby 台数を変更してコンソールが healthy に戻ったあとも、streaming replication が確立するまでさらに数分かかりました(0 → 2 の切替で実測約 5 分)
  • sync_state は最初 async で見え、その後 quorum へ切り替わる遷移を観測しました

4.2. レプリケーション関連の既定値(pg_settings より)

パラメータ 含意
wal_level logical replica より広い。論理レプリケーションも有効化されている(CH との連携を想定した既定と考えられます)
wal_compression lz4 WAL を LZ4 圧縮してから standby へ送る。クロス AZ で送るバイト量を削減
synchronous_commit on 同期 standby に対しては WAL flush 完了まで待つ ACK セマンティクス
archive_mode / archive_timeout on / 60 s WAL アーカイブ有効。1 分ごとに WAL switch(durability を多層化)
fsync / full_page_writes on / on durability を担保
hot_standby on standby は技術的には読み取り可能な構成だが、Docs どおり読み取り用には公開していない

synchronous_commit = on が確認できたことで、Docs の "at least one standby confirms" の "confirm" が WAL flush 完了レベルだと裏が取れました。


5. 計測結果

5.1. コミットレイテンシ(主指標)

3 回平均の latency average(単位 ms)。upd_c1 / upd_c8 は単発 UPDATE、sel_c1 は読み取りベースライン(pgbench -S)。

構成 upd_c1 upd_c8 sel_c1(読み取り) (upd_c1 − sel)
cfg0(なし) 4.242 4.184 3.917 +0.33
cfg1(1・非同期) 4.097 4.258 3.952 +0.15
cfg2(2・同期 quorum) 5.148 5.411 3.849 +1.30

構成間デルタ(同期 ACK の正味コスト):

比較 upd_c1 upd_c8
cfg2 − cfg1(同期 − 非同期) +1.05 ms +1.15 ms
cfg2 − cfg0(同期 − なし) +0.91 ms +1.23 ms
cfg1 − cfg0(非同期 − なし) −0.15 ms +0.07 ms(誤差)
  • 同期 standby を積むと、1 コミットあたり約 +1.0〜1.3 ms 重くなることが確認できました(非同期との差で +1.05〜1.15 ms、読み取りベースラインとの差で +1.30 ms。本記事ではこの幅を「約 +1.0〜1.3 ms」と表記します)
  • 非同期(1) と なし(0) の差は誤差範囲。「非同期は書き込みを遅くしない」が実測でも成立します
  • 読み取り(sel_c1)は 3.85〜3.95 ms で構成間 ±0.1 ms 以内。読み取りは standby を待たないことの裏返しです

5.2. レイテンシ分布(percentile)

per-transaction ログから算出しました。

構成 metric n avg p50 p95 p99 stdev
cfg0 upd_c1 42407 4.242 4.293 4.523 5.008 1.862
cfg1 upd_c1 43910 4.097 4.037 4.308 5.543 1.476
cfg2 upd_c1 34941 5.148 5.083 5.395 6.445 1.670
cfg0 upd_c8 343854 4.184 4.099 4.741 6.474 1.366
cfg1 upd_c8 337905 4.258 4.087 5.099 7.695 1.861
cfg2 upd_c8 265885 5.411 5.257 6.216 8.386 1.979

p99 でも cfg2 は cfg1 比で +0.7〜0.9 ms 高く、同期コストはテールにも一貫して乗っています。

5.3. 並列数を上げたときの TPS への影響

3 回平均の TPS です。

構成 -c64 -c128 -c64 比(cfg0=1.00) -c128 比
cfg0(なし) 5425.6 6043.7 1.00 1.00
cfg1(1・非同期) 5719.1 6713.3 1.05 1.11
cfg2(2・同期 quorum) 5064.1 5625.8 0.93 0.93

同期(cfg2)は非同期(cfg1)比で -c64 で約 -11%、-c128 で約 -16% の低下でした。

以下は計測期間を通したサーバ側コンソールメトリクスです。複数構成の pgbench 実行が時系列の山として現れます(構成ごとの定量値は上の表が正で、グラフは傾向の裏付けとして添えます)。前の山がcfg1、後ろの山がcfg2です。

metrics_conn_throughput_tx.png
5-1: 計測期間のサーバ側メトリクス — Operation Throughput(update)と Transactions(commits/s)。山の一つひとつが pgbench 実行

metrics_iops_cpu_mem.png
5-2: 計測期間のサーバ側メトリクス — IOPS / CPU / メモリ。user CPU はピーク約 70%、メモリは約 40% で一定(メモリ内で安定)

この TPS 低下は純粋な同期 ACK だけの影響ではありません。今回の Managed Postgres は 2 vCPU で、計測中の user CPU がピーク約 70% まで上がっています(5-2)。サーバ CPU の頭打ちも TPS に効いているため、ここは「同期で TPS が下がる傾向」として読み、定量値はコミットレイテンシ(5.1 章)を主に見るのが妥当です。


6. 考察

6.1. +1.0〜1.3 ms の正体

サーバ側のスロークエリ統計では、UPDATE 自体の平均は数百マイクロ秒(buffer hit 100%・コンソールメトリクスより)で、コミットレイテンシ 5 ms の大半はサーバの計算ではありません。synchronous_commit = on + quorum 同期なので、コミットは少なくとも 1 台の standby が WAL を flush するまで待ちます(synchronous_commit | PostgreSQL Docs)。したがって +1.0〜1.3 ms の正体は、クロス AZ の往復 1 回ぶん(+standby 側 NVMe の flush。これはマイクロ秒級で無視できる) とみられます。これが Docs の言う "additional network latency" の実体とみられます。

metrics_querylat_ops_bufferhit.png
6-1: Buffer hit 100%・UPDATE が呼び出しの 99%(すべてキャッシュから読み取り)

metrics_slow_query_patterns.png
6-2: サーバ側のクエリパターン別統計(UPDATE 自体はサブミリ秒)

6.2. 別環境での予備計測との差

別途、別環境(RTT 約 4 ms)から予備計測したときは同期コストが約 +1.5〜1.8 ms でしたが、AWS 同一リージョン内では約 +1.0〜1.3 ms と小さくなりました。これは AWS のリージョン内 AZ 間レイテンシがその環境からの往復より軽いことと、wal_compression = lz4 で standby へ送るバイト量が減ることが効いていると考えられます。

6.3. durability とのトレードオフ

同期(2 台)は「少なくとも 1 台の遠隔コピーが WAL を確定してからコミット」を保証するため(High availability | ClickHouse Docs)、primary が飛んでも直近のコミットが残ります。非同期(1 台)はその保証がなく、フェイルオーバー時に直近の数トランザクションを失い得ます。その引き換えに書き込みが +1.0〜1.3 ms/commit 重くなる、という関係です。耐久性そのもの(実際にどれだけ無損失か)は本記事では測っていません。

6.4. 検証できなかったこと

手動フェイルオーバーを発動する手段はコンソール・Docs に見当たらず、Restart は graceful な in-place 再起動でした(別途確認)。そのためフェイルオーバー自体の挙動・復旧時間は検証できていませんHigh availability | ClickHouse Docs は「standby があれば数分で復旧」と述べており、本記事ではその引用に留めます。

6.5. サーバ CPU の影響

並列数を上げたときの TPS の低下(5.3 章)は、2 vCPU・user CPU 約 70% という条件下のため、同期 ACK の影響とサーバ CPU の頭打ちが混在しています。同期コストを純粋に見たい場合は、低並列のコミットレイテンシ(5.1 章)の方が信頼できます。


7. まとめ

観点 本検証の結論
同期 standby のトレードオフ コミットあたり 約 +1.0〜1.3 ms(非同期比)。Docs の "additional network latency" の実体
読み取り 構成 0/1/2 でほぼ不変(standby は読み取りの経路に入らない)
非同期 vs なし コミットレイテンシはほぼ同じ(非同期は書き込みを遅くしない)
並列数を上げたときの TPS 同期で -c64 約 -11% / -c128 約 -16%(ただし 2 vCPU のサーバ CPU 影響が混在)
実装 AWS の上に素の PostgreSQL ストリーミング+quorum 同期を載せた論理的な仕組み。RDS Multi-AZ とは別物

使い分けの目安:

要件 推奨
書き込みレイテンシ最優先・HA も欲しい standby 1(非同期)。書き込みを遅くせず冗長化
直近コミットの無損失(強い durability)を優先 standby 2(同期 quorum)。トレードオフは +1 ms 前後/commit
読み取りスケール standby ではなく read replica を別途

「HA を有効にすると遅くなるのか?」は、非同期なら実質ノーコスト、同期で約 +1 ms/commit という、構成で選べるトレードオフでした。


参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?