最近、KubernetesにてPostgreSQL Operatorで楽に冗長構成が作れることを知った阿部です。
クラウドサービスのマネージドなPostgreSQLではPGroongaが使えないところが多く、自分で運用しないといけないケースがあります。 そんなときに、KubernetesのPostgreSQL Operatorで作った冗長構成でPGroongaを使えれば、運用が楽になるかもしれません。
ということで、その楽に作れる冗長構成にPGroongaも乗せられるか試してみます。
はじめに
Kubernetes関連の準備は整っているとします。今回はkindで検証するので、具体的にはdocker、kind、kubectlコマンドが使える状態になっているとします。
まずはPostgreSQLの冗長構成がどのようなものか確認し、PGroongaも乗せるとどうなるか確認していきます。
今回の確認はKubernetes上でPGroongaの冗長構成が作れるかを確かめるための簡易的なものです。
テーブル構成はシンプル、データ量は数行、障害はkubectl deleteでPodを停止させただけ、など実際のサービスの環境や発生しそうな障害を再現しているとは言えない検証であることを踏まえてご覧ください。
次の流れで説明します。
- KubernetesでPostgreSQLの冗長構成を作る
- KubernetesでPGroongaを1台構成で動かす
- KubernetesでPostgreSQL + PGroongaの冗長構成を作る
0. 準備
検証用のKubernetesクラスタを作っておきます。
kind create cluster
CloudNativePGをインストールします。 (バージョンは適宜変えてください。)
kubectl apply --server-side -f \
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.30/releases/cnpg-1.30.1.yaml
CloudNativePGは、Kubernetes上でPostgreSQLを自動で運用してくれるOperatorです。 Operatorは運用担当者に代わって自動でいろいろやってくれるKubernetesの拡張です。 簡単な設定でprimaryとreplicaを作ってくれて、何かトラブルがあったらフェイルオーバーもしてくれます。
参考: https://kubernetes.io/ja/docs/concepts/extend-kubernetes/operator/
1. KubernetesでPostgreSQLの冗長構成を作る
cat <<YAML > ha.yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgres
spec:
instances: 3
storage:
size: 1Gi
YAML
kubectl apply --filename ha.yaml
↑のコマンドを実行する前に、別のターミナルで↓のコマンドを実行しておくと起動の様子が確認できます。
今回はPodの役割(primary or replica)も確認したいのでcnpg.io/instanceRoleも一緒に表示しつつ状況を確認します。
$ kubectl get pods --label-columns cnpg.io/instanceRole --watch
NAME READY STATUS RESTARTS AGE INSTANCEROLE
postgres-1-initdb-8fghk 0/1 Pending 0 0s
postgres-1-initdb-8fghk 0/1 Pending 0 0s
postgres-1-initdb-8fghk 0/1 Pending 0 4s
postgres-1-initdb-8fghk 0/1 Init:0/1 0 4s
postgres-1-initdb-8fghk 0/1 Init:0/1 0 5s
postgres-1-initdb-8fghk 0/1 Init:0/1 0 5s
postgres-1-initdb-8fghk 0/1 PodInitializing 0 6s
postgres-1-initdb-8fghk 1/1 Running 0 27s
postgres-1-initdb-8fghk 0/1 Completed 0 29s
postgres-1-initdb-8fghk 0/1 Completed 0 30s
postgres-1-initdb-8fghk 0/1 Completed 0 30s
postgres-1 0/1 Pending 0 0s
postgres-1 0/1 Pending 0 0s
postgres-1 0/1 Init:0/1 0 0s
postgres-1 0/1 Init:0/1 0 1s
postgres-1 0/1 Init:0/1 0 1s
postgres-1 0/1 PodInitializing 0 2s
postgres-1 0/1 Running 0 2s
postgres-1 0/1 Running 0 4s primary
postgres-1 0/1 Running 0 11s primary
postgres-1 1/1 Running 0 11s primary
postgres-2-join-md67l 0/1 Pending 0 0s
postgres-2-join-md67l 0/1 Pending 0 0s
postgres-2-join-md67l 0/1 Pending 0 3s
postgres-2-join-md67l 0/1 Init:0/1 0 3s
postgres-2-join-md67l 0/1 Init:0/1 0 3s
postgres-2-join-md67l 0/1 Init:0/1 0 4s
postgres-2-join-md67l 0/1 PodInitializing 0 4s
postgres-2-join-md67l 1/1 Running 0 4s
postgres-2-join-md67l 0/1 Completed 0 7s
postgres-2-join-md67l 0/1 Completed 0 8s
postgres-2-join-md67l 0/1 Completed 0 9s
postgres-2 0/1 Pending 0 0s
postgres-2 0/1 Pending 0 0s
postgres-2 0/1 Init:0/1 0 0s
postgres-2 0/1 Init:0/1 0 0s
postgres-2 0/1 Init:0/1 0 1s
postgres-2 0/1 PodInitializing 0 1s
postgres-2 0/1 Running 0 1s
postgres-2 0/1 Running 0 3s replica
postgres-2 0/1 Running 0 10s replica
postgres-2 1/1 Running 0 11s replica
postgres-3-join-gkclv 0/1 Pending 0 0s
postgres-3-join-gkclv 0/1 Pending 0 0s
postgres-3-join-gkclv 0/1 Pending 0 3s
postgres-3-join-gkclv 0/1 Init:0/1 0 3s
postgres-3-join-gkclv 0/1 Init:0/1 0 4s
postgres-3-join-gkclv 0/1 Init:0/1 0 4s
postgres-3-join-gkclv 0/1 PodInitializing 0 4s
postgres-3-join-gkclv 1/1 Running 0 4s
postgres-3-join-gkclv 0/1 Completed 0 5s
postgres-3-join-gkclv 0/1 Completed 0 6s
postgres-3-join-gkclv 0/1 Completed 0 6s
postgres-3 0/1 Pending 0 0s
postgres-3 0/1 Pending 0 0s
postgres-3 0/1 Init:0/1 0 0s
postgres-3 0/1 Init:0/1 0 1s
postgres-3 0/1 Init:0/1 0 1s
postgres-3 0/1 PodInitializing 0 1s
postgres-3 0/1 Running 0 1s
postgres-3 0/1 Running 0 3s replica
postgres-3 0/1 Running 0 11s replica
postgres-3 1/1 Running 0 11s replica
postgres-1-initdb-8fghk 0/1 Completed 0 78s
postgres-2-join-md67l 0/1 Completed 0 37s
postgres-1-initdb-8fghk 0/1 Completed 0 78s
postgres-3-join-gkclv 0/1 Completed 0 17s
postgres-2-join-md67l 0/1 Completed 0 37s
postgres-3-join-gkclv 0/1 Completed 0 17s
起動したら、次の3点を確認していきます。
- primaryに書き込み + レプリケーションされていることを確認
- primaryを停止、その後replicaがprimaryに昇格するのを確認
- 新primaryに書き込み + レプリケーションされていることを確認
- 旧primaryを含めレプリケーションされていることを確認
primaryに書き込み + レプリケーションされていることを確認
CloudNativePGはアプリ用にappというデータベースを作ってくれるのでそれを使います。
primaryであるpostgres-1にテーブルを作ってデータをinsertします。
$ kubectl exec -it postgres-1 --container=postgres -- psql -d app --command "
CREATE TABLE test (id serial, message text);
INSERT INTO test (message) VALUES ('MESSAGE 1');
SELECT * FROM test;
"
CREATE TABLE
INSERT 0 1
id | message
----+-----------
1 | MESSAGE 1
(1 row)
replicaであるpostgres-2とpostgres-3にも届いているか確認します。
$ kubectl exec -it postgres-2 --container=postgres -- psql -d app --command "SELECT * FROM test;"
id | message
----+-----------
1 | MESSAGE 1
(1 row)
$ kubectl exec -it postgres-3 --container=postgres -- psql -d app --command "SELECT * FROM test;"
id | message
----+-----------
1 | MESSAGE 1
(1 row)
primaryがpostgres-1、replicaがpostgres-2とpostgres-3で起動したことが確認できました。
ちゃんとreplicaには書き込めません。
$ kubectl exec -it postgres-2 --container=postgres -- \
psql -d app --command "INSERT INTO test (message) VALUES ('MESSAGE ERROR');"
ERROR: cannot execute INSERT in a read-only transaction
command terminated with exit code 1
primaryを停止、その後replicaがprimaryに昇格するのを確認
「postgres-1に何かトラブルがあって落ちた」というテイでprimaryのpostgres-1をdeleteします。
その後、replicaがprimaryに切り替わり、落ちたpostgres-1がreplicaとして復活してくることを確認します。 切り替わる様子を確認するために、起動の様子を確認した次のコマンドを別ターミナルで実行しておくと良いです。
kubectl get pods --label-columns cnpg.io/instanceRole --watch
primaryをdeleteします。
kubectl delete pod postgres-1
get podsには次のように表示され、postgres-2がprimaryになり、停止されたpostgres-1がreplicaで復活してきたことが確認できます。
postgres-1 1/1 Terminating 0 23h primary
postgres-1 1/1 Terminating 0 23h primary
postgres-1 1/1 Terminating 0 23h unhealthy
postgres-1 0/1 Completed 0 23h unhealthy
postgres-1 0/1 Completed 0 23h unhealthy
postgres-1 0/1 Completed 0 23h unhealthy
postgres-2 1/1 Running 0 23h primary
postgres-1 0/1 Pending 0 0s
postgres-1 0/1 Pending 0 0s
postgres-1 0/1 Init:0/1 0 0s
postgres-1 0/1 Init:0/1 0 0s
postgres-1 0/1 Init:0/1 0 0s
postgres-1 0/1 PodInitializing 0 0s
postgres-1 0/1 Running 0 0s
postgres-1 0/1 Running 0 2s replica
postgres-1 0/1 Running 0 10s replica
postgres-1 1/1 Running 0 10s replica
新primaryに書き込み + レプリケーションされていることを確認
primaryであるpostgres-2にinsertします。先ほどreplicaだったときはエラーになりましたが、今回は書き込めます。
$ kubectl exec -it postgres-2 --container=postgres -- psql -d app --command "
SELECT * FROM test;
INSERT INTO test (message) VALUES ('MESSAGE 2');
SELECT * FROM test;
"
id | message
----+-----------
1 | MESSAGE 1
(1 row)
INSERT 0 1
id | message
----+-----------
1 | MESSAGE 1
34 | MESSAGE 2
(2 rows)
replicaに届いていることも確認します。
$ kubectl exec -it postgres-1 --container=postgres -- psql -d app --command "SELECT * FROM test;"
id | message
----+-----------
1 | MESSAGE 1
34 | MESSAGE 2
(2 rows)
$ kubectl exec -it postgres-3 --container=postgres -- psql -d app --command "SELECT * FROM test;"
id | message
----+-----------
1 | MESSAGE 1
34 | MESSAGE 2
(2 rows)
フェイルオーバーの詳細: https://cloudnative-pg.io/docs/1.30/failover/
補足: CloudNativePGのkubectlプラグインを使う
CloudNativePGのkubectlプラグインを使うとreplicaをprimaryに昇格させる、などの操作ができます。
参考: https://cloudnative-pg.io/docs/1.30/kubectl-plugin/#promote
# プラグインのインストール
curl -sSfL https://github.com/cloudnative-pg/cloudnative-pg/raw/main/hack/install-cnpg-plugin.sh | sh -s -- -b /usr/local/bin
kubectl cnpg version
get podsしておくと切り替えの様子が確認できます。
次のコマンドでpostgres-1をprimaryに戻せます。
kubectl cnpg promote postgres postgres-1
ログ:
postgres-2 1/1 Running 0 23h unhealthy
postgres-2 0/1 Completed 0 23h unhealthy
postgres-2 0/1 Running 1 (1s ago) 23h unhealthy
postgres-1 1/1 Running 0 18m primary
postgres-2 0/1 Running 1 (6s ago) 23h replica
postgres-2 0/1 Running 1 (13s ago) 23h replica
postgres-2 1/1 Running 1 (13s ago) 23h replica
2. KubernetesでPGroongaを1台構成で動かす
PostgreSQLで冗長構成が作れたことが確認できました。 次はこれにPGroongaを乗せても動くのか!?を確認します。
ということで、冗長構成の前にKubernetesでPGroongaを動かす方法を見ていきます。
いろいろやり方はあるのですが、今回はCloudNativePGのImage Catalogを使って、PGroongaの公式Dockerイメージで起動する方法を試します。 とりあえず1台だけ起動してPGroongaが動く様子を確認します。
cat <<YAML > pgroonga.yaml
apiVersion: postgresql.cnpg.io/v1
kind: ImageCatalog
metadata:
name: pgroonga-image
spec:
images:
- major: 18
image: groonga/pgroonga:4.1.0-debian-18
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pgroonga
spec:
instances: 1
imageCatalogRef:
apiGroup: postgresql.cnpg.io
kind: ImageCatalog
name: pgroonga-image
major: 18
postgresUID: 999
postgresGID: 999
storage:
size: 1Gi
YAML
kubectl apply --filename pgroonga.yaml
補足: CloudNativePGの公式イメージとUID/GIDが違うのでそれも指定しています。
これも別ターミナルでget podsしておくと起動の様子が確認できますが、表示される内容はPostgreSQLのときとだいたい同じなので割愛します。
起動したらデータを投入して全文検索ができるか確認します。
$ kubectl exec -it pgroonga-1 --container=postgres -- psql -d app --command "
CREATE EXTENSION pgroonga;
CREATE TABLE memos (id integer, content text);
CREATE INDEX pgroonga_content_index ON memos USING pgroonga (content);
INSERT INTO memos VALUES (1, 'PostgreSQLはリレーショナル・データベース管理システムです。');
INSERT INTO memos VALUES (2, 'Groongaは日本語対応の高速な全文検索エンジンです。');
INSERT INTO memos VALUES (3, 'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。');
INSERT INTO memos VALUES (4, 'groongaコマンドがあります。');
SET enable_seqscan = off;
EXPLAIN SELECT * FROM memos WHERE content &@ '全文検索';
SELECT * FROM memos WHERE content &@ '全文検索';
"
CREATE EXTENSION
CREATE TABLE
CREATE INDEX
INSERT 0 1
INSERT 0 1
INSERT 0 1
INSERT 0 1
SET
QUERY PLAN
--------------------------------------------------------------------------------------
Index Scan using pgroonga_content_index on memos (cost=0.00..43.18 rows=1 width=36)
Index Cond: (content &@ '全文検索'::text)
(2 rows)
id | content
----+---------------------------------------------------
2 | Groongaは日本語対応の高速な全文検索エンジンです。
(1 row)
全文検索できました!
3. KubernetesでPostgreSQL + PGroongaの冗長構成を作る
いよいよ本題のKubernetesでPostgreSQL + PGroongaで冗長構成が作れるのか!?を確認します。
postgresql:でPGroongaのレプリケーションに最低限必要な設定をします。
あくまで検証用の設定なので、実際の運用時はドキュメントを参照の上、必要な設定をしてください。
参考: WALリソースマネージャーを使ったストリーミングレプリケーション
kubectl delete cluster pgroonga
cat <<YAML > pgroonga-ha.yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pgroonga-ha
spec:
instances: 3
imageCatalogRef:
apiGroup: postgresql.cnpg.io
kind: ImageCatalog
name: pgroonga-image
major: 18
postgresUID: 999
postgresGID: 999
postgresql:
shared_preload_libraries:
- pgroonga_wal_resource_manager
parameters:
pgroonga.enable_wal_resource_manager: "on"
storage:
size: 1Gi
YAML
kubectl apply --filename pgroonga-ha.yaml
これも別ターミナルでget podsしておくと起動の様子が確認できます。
上述したプラグインを使うとどれがprimaryでどれがreplicaかを確認することもできます。
$ kubectl cnpg status pgroonga-ha
Cluster Summary
Name default/pgroonga-ha
System ID: 7703151592466559006
PostgreSQL Image: groonga/pgroonga:4.1.0-debian-18
Primary instance: pgroonga-ha-1
Primary promotion time: 2026-11-01 23:42:28 +0000 UTC (4m52s)
Status: Cluster in healthy state
Instances: 3
Ready instances: 3
Size: 129M
Current Write LSN: 0/61F8220 (Timeline: 1 - WAL File: 000000010000000000000006)
Continuous Backup not configured
Streaming Replication status
Replication Slots Enabled
Name Sent LSN Write LSN Flush LSN Replay LSN Write Lag Flush Lag Replay Lag State Sync State Sync Priority Replication Slot
---- -------- --------- --------- ---------- --------- --------- ---------- ----- ---------- ------------- ----------------
pgroonga-ha-2 0/61F8220 0/61F8220 0/61F8220 0/61F8220 00:00:00 00:00:00 00:00:00 streaming async 0 active
pgroonga-ha-3 0/61F8220 0/61F8220 0/61F8220 0/61F8220 00:00:00 00:00:00 00:00:00 streaming async 0 active
Instances status
Name Current LSN Replication role Status QoS Manager Version Node
---- ----------- ---------------- ------ --- --------------- ----
pgroonga-ha-1 0/61F8220 Primary OK BestEffort 1.30.1 kind-control-plane
pgroonga-ha-2 0/61F8220 Standby (async) OK BestEffort 1.30.1 kind-control-plane
pgroonga-ha-3 0/61F8220 Standby (async) OK BestEffort 1.30.1 kind-control-plane
pgroonga-ha-1がprimaryで、pgroonga-ha-{2,3}がreplicaです。
さっそくpgroonga-ha-1にデータをinsertして、pgroonga-ha-{2,3}にもレプリケーションされているか確認します。
$ kubectl exec -it pgroonga-ha-1 --container=postgres -- psql -d app --command "
CREATE EXTENSION pgroonga;
CREATE TABLE memos (id integer, content text);
CREATE INDEX pgroonga_content_index ON memos USING pgroonga (content);
INSERT INTO memos VALUES (1, 'PostgreSQLはリレーショナル・データベース管理システムです。');
INSERT INTO memos VALUES (2, 'Groongaは日本語対応の高速な全文検索エンジンです。');
INSERT INTO memos VALUES (3, 'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。');
INSERT INTO memos VALUES (4, 'groongaコマンドがあります。');
SET enable_seqscan = off;
EXPLAIN SELECT * FROM memos WHERE content &@ '全文検索';
SELECT * FROM memos WHERE content &@ '全文検索';
"
CREATE EXTENSION
CREATE TABLE
CREATE INDEX
INSERT 0 1
INSERT 0 1
INSERT 0 1
INSERT 0 1
SET
QUERY PLAN
--------------------------------------------------------------------------------------
Index Scan using pgroonga_content_index on memos (cost=0.00..43.18 rows=1 width=36)
Index Cond: (content &@ '全文検索'::text)
(2 rows)
id | content
----+---------------------------------------------------
2 | Groongaは日本語対応の高速な全文検索エンジンです。
(1 row)
primaryにinsertして全文検索ができました。replicaの確認もします。
$ kubectl exec -it pgroonga-ha-2 --container=postgres -- psql -d app --command "
SET enable_seqscan = off;
EXPLAIN SELECT * FROM memos WHERE content &@ '全文検索';
SELECT * FROM memos WHERE content &@ '全文検索';
"
SET
QUERY PLAN
--------------------------------------------------------------------------------------
Index Scan using pgroonga_content_index on memos (cost=0.00..43.18 rows=1 width=36)
Index Cond: (content &@ '全文検索'::text)
(2 rows)
id | content
----+---------------------------------------------------
2 | Groongaは日本語対応の高速な全文検索エンジンです。
(1 row)
$ kubectl exec -it pgroonga-ha-3 --container=postgres -- psql -d app --command "
SET enable_seqscan = off;
EXPLAIN SELECT * FROM memos WHERE content &@ '全文検索';
SELECT * FROM memos WHERE content &@ '全文検索';
"
SET
QUERY PLAN
--------------------------------------------------------------------------------------
Index Scan using pgroonga_content_index on memos (cost=0.00..43.18 rows=1 width=36)
Index Cond: (content &@ '全文検索'::text)
(2 rows)
id | content
----+---------------------------------------------------
2 | Groongaは日本語対応の高速な全文検索エンジンです。
(1 row)
レプリケーションもOKです。 次はprimaryがトラブルで落ちたテイでdeleteします。
$ kubectl delete pod pgroonga-ha-1
pod "pgroonga-ha-1" deleted from default namespace
$ kubectl cnpg status pgroonga-ha
Cluster Summary
Name default/pgroonga-ha
System ID: 7703151592466559006
PostgreSQL Image: groonga/pgroonga:4.1.0-debian-18
Primary instance: pgroonga-ha-2
Primary promotion time: 2026-11-01 23:54:26 +0000 UTC (30s)
Status: Cluster in healthy state
Instances: 3
Ready instances: 3
Size: 178M
Current Write LSN: 0/B000000 (Timeline: 2 - WAL File: 00000002000000000000000B)
Continuous Backup not configured
Streaming Replication status
Replication Slots Enabled
Name Sent LSN Write LSN Flush LSN Replay LSN Write Lag Flush Lag Replay Lag State Sync State Sync Priority Replication Slot
---- -------- --------- --------- ---------- --------- --------- ---------- ----- ---------- ------------- ----------------
pgroonga-ha-1 0/B000000 0/B000000 0/B000000 0/B000000 00:00:00 00:00:00 00:00:00 streaming async 0 active
pgroonga-ha-3 0/B000000 0/B000000 0/B000000 0/B000000 00:00:00 00:00:00 00:00:00 streaming async 0 active
Instances status
Name Current LSN Replication role Status QoS Manager Version Node
---- ----------- ---------------- ------ --- --------------- ----
pgroonga-ha-2 0/B000000 Primary OK BestEffort 1.30.1 kind-control-plane
pgroonga-ha-1 0/B000000 Standby (async) OK BestEffort 1.30.1 kind-control-plane
pgroonga-ha-3 0/B000000 Standby (async) OK BestEffort 1.30.1 kind-control-plane
pgroonga-ha-2がprimaryになって、pgroonga-ha-1はreplicaになりました。
新primaryにinsertして確認します。
$ kubectl exec -it pgroonga-ha-2 --container=postgres -- psql -d app --command "
INSERT INTO memos VALUES (5, 'pgroonga-ha-2 new primary! Groongaは日本語対応の高速な全文検索エンジンです。');
SET enable_seqscan = off;
EXPLAIN SELECT * FROM memos WHERE content &@ '全文検索';
SELECT * FROM memos WHERE content &@ '全文検索';
"
INSERT 0 1
SET
QUERY PLAN
--------------------------------------------------------------------------------------
Index Scan using pgroonga_content_index on memos (cost=0.00..50.16 rows=1 width=36)
Index Cond: (content &@ '全文検索'::text)
(2 rows)
id | content
----+------------------------------------------------------------------------------
2 | Groongaは日本語対応の高速な全文検索エンジンです。
5 | pgroonga-ha-2 new primary! Groongaは日本語対応の高速な全文検索エンジンです。
(2 rows)
replicaも確認します。(pgroonga-ha-1の結果だけ記載しますが、pgroonga-ha-3も同じ結果でした。)
$ kubectl exec -it pgroonga-ha-1 --container=postgres -- psql -d app --command "
SET enable_seqscan = off;
EXPLAIN SELECT * FROM memos WHERE content &@ '全文検索';
SELECT * FROM memos WHERE content &@ '全文検索';
"
SET
QUERY PLAN
--------------------------------------------------------------------------------------
Index Scan using pgroonga_content_index on memos (cost=0.00..50.16 rows=1 width=36)
Index Cond: (content &@ '全文検索'::text)
(2 rows)
id | content
----+------------------------------------------------------------------------------
2 | Groongaは日本語対応の高速な全文検索エンジンです。
5 | pgroonga-ha-2 new primary! Groongaは日本語対応の高速な全文検索エンジンです。
(2 rows)
replicaにも反映されました!
KubernetesでPostgreSQL + PGroongaの冗長構成ができました!
注意
今回はkubectl deleteで正常に停止させたので、pgroonga-ha-1は問題なくreplicaとして起動できました。
しかし、実際の障害ではプロセスが突然終了するなど、想定外の止まり方をすることがあります。
そのようなケースでは復活したpgroonga-ha-1のPGroongaのインデックスが壊れている可能性があります。
壊れていた場合はインデックスを作り直すなどの対応が必要です。
まとめ
KubernetesでPostgreSQL + PGroongaの冗長構成を確認できました。 ただし「はじめに」に書いた通り、実際のサービスの環境や発生しそうな障害を再現しているとは言えない検証での確認です。
もう少し実際の環境に近い検証もしたいと思います。
今回は簡易的な検証でしたが、より実環境に近い環境を構築し検証、改善案の提案もできますので、PGroongaやPostgreSQLの運用でお困りの場合はお問い合わせよりご連絡ください。