コネクションプーリング¶
CloudNativePGは、 Pooler
CRDを介して、PostgreSQL用の最も一般的なオープンソース接続プーラーの1つである
PgBouncerIntegrationStatus を使用した接続プーリングのネイティブサポートを提供します。
簡単に言えば、CloudNativePGのPooler
は、アプリケーションとPostgreSQLサービス( rw
サービスなど)の間にあるPgBouncerポッドのデプロイであり、別個のスケーラブルで構成可能な高可用性
データベースアクセスレイヤー を作成します。
アーキテクチャ¶
次の図は、PgBouncerに基づくデータベースアクセスレイヤーの導入により、スイスアーミーナイフの追加のブレードのように、CloudNativePGのアーキテクチャがどのように変わるかを強調しています。 PostgreSQLプライマリサービスに直接接続する代わりに、アプリケーションはPgBouncerの同等のサービスに接続できるようになり、既存の接続を再利用して、PostgreSQL側でのパフォーマンスの高速化とリソース管理の向上を実現できます。
Applications writing to the single primary via PgBouncer¶
クイックスタート¶
CloudNativePGがPgBouncerプーラーを実装する方法を説明する最も簡単な方法は、例です。
apiVersion: postgresql.cnpg.io/v1
kind: Pooler
metadata:
name: pooler-example-rw
spec:
cluster:
name: cluster-example
instances: 3
type: rw
pgbouncer:
poolMode: session
parameters:
max_client_conn: "1000"
default_pool_size: "10"
重要
プーラー名は、同じ名前空間内のクラスター名と一致してはなりません。
これにより、 pooler-example-rw
(名前は任意)と呼ばれる新しいPooler リソースが作成されます。
Pooler
は、Postgresクラスターと同じ名前空間に存在する必要があります。
を実行する3つのポッドのKubernetesデプロイメントで構成されています
それぞれ最大1000個の接続を受け入れます-PostgreSQLに対するデフォルトのプールサイズは10ユーザー/データベースペアです。
重要
Pooler はPgBouncerに`*` フォールバックデータベースのみを設定します。つまり、クライアントから渡された接続文字列のすべてのパラメーターはPostgreSQLサーバーに中継されます(["Section [databases]" in PgBouncer's documentation](https://www.pgbouncer.org/config.html#section-databases)を参照してください)。
さらに、CloudNativePGは、PgBouncerで使用される構成ファイルを含むプーラーと同じ名前のシークレットを自動的に作成します。
APIリファレンスで。
プーラーリソースのライフサイクル¶
Pooler リソースはCluster
管理のリソースではありません。プーラーは、必要に応じて手動で作成することになっています。さらに、PostgreSQLクラスターごとに複数のプーラーをデプロイできます。
Cluster とPooler
リソースのライフサイクルは現在独立していることに注意することが重要です。
Cluster の削除は、 Pooler
の自動削除を意味するものではなく、その逆も同様です。
重要
Pooler がどのように機能するかがわかったので、可能なアーキテクチャに関して完全に自由があります。プーラーのないクラスター、単一のプーラーを持つクラスター、または複数のプーラーを持つクラスター(つまり、アプリケーションごとに1つ)を持つことができます。
セキュリティ¶
PgBouncerプーラーは、プールのクライアント(アプリケーション)側とサーバー(PostgreSQL)側の両方で、 TLS接続 を介した転送中の暗号化のCloudNativePGサポートと透過的に統合されます。
具体的には、PgBouncerはPostgreSQLサーバーの証明書を自動的に再利用します。さらに、TLSクライアント証明書認証を使用してPostgreSQLサーバーに接続し、クライアントのパスワード認証のためにauth_query
を実行します(以下の 認証の使用 を参照)。
コンテナはpgbouncer システムユーザーとして実行され、 pgbouncer
データベースへのアクセスは、 peer
認証を介したローカル接続を介してのみ許可されます。
証明書¶
デフォルトでは、PgBouncerプーラーはクラスター自分自身が使用するのと同じ証明書を使用しますが、ユーザーがこれらの証明書を提供すると、プーラーは次の形式のシークレットを受け入れます。
1.基本認証
2.TLS
3.不透明
不透明な場合、使用する必要がある特定のキーを探します。それらのキーは次のとおりです。
tls.crt
tls.key
したがって、このシークレットをTLSシークレットとして扱い、そこから始めることができます。
認証¶
パスワードベースの認証 は、CloudNativePGのPgBouncerのクライアントでサポートされている唯一の方法です。
内部的に、私たちの実装はPgBouncerのauth_user
およびauth_query
オプションに依存しています。具体的には、オペレーターは次のことを行います。
PostgreSQLサーバーに
cnpg_pooler_pgbouncerという標準ユーザーを作成しますpostgresデータベースにルックアップ関数を作成し、cnpg_pooler_pgbouncerユーザーに実行権限を付与します(PoLA)このユーザーのTLS証明書を発行します
cnpg_pooler_pgbouncerをauth_userとして設定しますTLS証明書を使用してPostgreSQLサーバーに対して
cnpg_pooler_pgbouncerを認証するようにPgBouncerを構成しますクラスターにプーラーが関連付けられていないことを検出すると、上記すべてを削除します
重要
独自のシークレットを指定した場合、オペレーターはプーラーを自動的に統合しません。
独自のシークレットを指定した場合にプーラーを手動で統合するには、クラスター内から次のクエリを実行する必要があります。
まず、ロールを作成する必要があります。
CREATE ROLE cnpg_pooler_pgbouncer WITH LOGIN;
次に、アプリケーションデータベースごとに、 cnpg_pooler_pgbouncer
に接続する権限を付与します。
GRANT CONNECT ON DATABASE { database name here } TO cnpg_pooler_pgbouncer;
最後に、各アプリケーションデータベースに接続し、各アプリケーションデータベース内に認証関数を作成します。
CREATE OR REPLACE FUNCTION user_search(uname TEXT)
RETURNS TABLE (usename name, passwd text)
LANGUAGE sql SECURITY DEFINER AS
SELECT usename, passwd FROM pg_shadow WHERE usename=$1;;
REVOKE ALL ON FUNCTION user_search(text)
FROM public;
GRANT EXECUTE ON FUNCTION user_search(text)
TO cnpg_pooler_pgbouncer;
ポッドテンプレート¶
Pooler リソースのtemplate
セクションでポッドテンプレート仕様を利用できます。詳細はAPIリファレンスの`PoolerSpec
section <api_reference.md#PoolerSpec>`__を参照してください。
テンプレートを使用して、ポッドとノードのアフィニティおよび非アフィニティルールの微調整など、ポッドを好きなように構成できます。デフォルトでは、コンテナはghcr.io/cloudnative-pg/pgbouncer
のイメージを使用します。
ここにPodAntiAffinityを指定するプーラーの例:
apiVersion: postgresql.cnpg.io/v1
kind: Pooler
metadata:
name: pooler-example-rw
spec:
cluster:
name: cluster-example
instances: 3
type: rw
template:
metadata:
labels:
app: pooler
spec:
containers: []
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- pooler
topologyKey: "kubernetes.io/hostname"
注釈
.spec.template.spec.containers は`PodSpec` の必須フィールドであるため、変更されない場合は明示的に`[]` に設定する必要があります。 .spec.template.spec.containers が設定されていない場合、マニフェストを適用しようとするとkubernetes api-serverは次のエラーを返します。error validating "pooler.yaml": error validating data: ValidationError(Pooler.spec.template.spec): missing required field "containers"
ここでは、リソースを設定し、使用される画像を変更する例を示します。
apiVersion: postgresql.cnpg.io/v1
kind: Pooler
metadata:
name: pooler-example-rw
spec:
cluster:
name: cluster-example
instances: 3
type: rw
template:
metadata:
labels:
app: pooler
spec:
containers:
- name: pgbouncer
image: my-pgbouncer:latest
resources:
requests:
cpu: "0.1"
memory: 100Mi
limits:
cpu: "0.5"
memory: 500Mi
高可用性(HA)¶
Kubernetesの展開のおかげで、プーラーを単一のインスタンスまたは複数のポッドで実行するように構成できます。公開されたサービスにより、PgBouncerを実行している利用可能なポッドにクライアントがランダムに分散されます。 。
警告
インフラストラクチャが複数のアベイラビリティーゾーンにまたがり、レイテンシーが高い場合は、ネットワークホップに注意してください。たとえば、ゾーン2で実行されているアプリケーション、ゾーン3で実行されているPgBouncerに接続し、ゾーン1のPostgreSQLプライマリをポイントしている場合を考えます。
PgBouncer構成オプション¶
オペレーターは configuration options for PgBouncer のほとんどを管理し、それらのサブセットのみを変更できるようにします。
警告
オペレーターは各オプションの値を検証しないため、各オプションの値を正しく設定する責任があります。
以下に、カスタマイズが許可されているPgBouncerオプションのリストを示します。それぞれには、その特定のパラメーターのPgBouncerドキュメントへのリンクが含まれています。ここで特に断りのない限り、デフォルト値はPgBouncerによって直接設定された値です。
ignore_startup_parameters :
extra_float_digits,optionsに追加されます -
CNPが必要
log_stats :デフォルトでは無効(
0
)、統計は以下の MonitoringConfiguration セクションで説明するようにPrometheusエクスポートによって既に収集されている場合
PgBouncer構成のカスタマイズは、 .spec.pgbouncer.parameters
マップに宣言的に書き込まれます。
オペレーターはプーラー仕様の変更に反応し、すべてのPgBouncerインスタンスはサービスを中断することなく更新された構成をリロードします。
警告
すべてのPgBouncer Podは、仕様のパラメーターに合わせて、同じ構成になります。これらのパラメーターに誤りがあると、プーラー全体**の操作性が混乱する可能性があります。演算子は、オプションの値を検証しません。
モニタリング¶
Pooler
のPgBouncer実装には、デフォルトのPrometheusエクスポーターが付属しています。これは、次を実行して、
cnpg_pgbouncer_
プレフィックスを持ついくつかのメトリックを自動的に利用可能にします。
SHOW LISTS(プレフィックス:cnpg_pgbouncer_lists)SHOW POOLS(プレフィックス:cnpg_pgbouncer_pools)SHOW STATS(プレフィックス:cnpg_pgbouncer_stats)
CloudNativePGインスタンスと同様に、エクスポーターはPgBouncerを実行している各ポッドのポート9127
で実行され、Goランタイムに関連するメトリックも提供します(プレフィックスgo_*
)。次のコマンドを使用して、PgBouncerを実行しているポッドでエクスポーターをデバッグできます。
kubectl exec -ti <PGBOUNCER_POD> -- curl 127.0.0.1:9127/metrics
cnpg_pgbouncer メトリックの出力例:
# HELP cnpg_pgbouncer_collection_duration_seconds Collection time duration in seconds
# TYPE cnpg_pgbouncer_collection_duration_seconds gauge
cnpg_pgbouncer_collection_duration_seconds{collector="Collect.up"} 0.002443168
# HELP cnpg_pgbouncer_collections_total Total number of times PostgreSQL was accessed for metrics.
# TYPE cnpg_pgbouncer_collections_total counter
cnpg_pgbouncer_collections_total 1
# HELP cnpg_pgbouncer_last_collection_error 1 if the last collection ended with error, 0 otherwise.
# TYPE cnpg_pgbouncer_last_collection_error gauge
cnpg_pgbouncer_last_collection_error 0
# HELP cnpg_pgbouncer_lists_databases Count of databases.
# TYPE cnpg_pgbouncer_lists_databases gauge
cnpg_pgbouncer_lists_databases 1
# HELP cnpg_pgbouncer_lists_dns_names Count of DNS names in the cache.
# TYPE cnpg_pgbouncer_lists_dns_names gauge
cnpg_pgbouncer_lists_dns_names 0
# HELP cnpg_pgbouncer_lists_dns_pending Not used.
# TYPE cnpg_pgbouncer_lists_dns_pending gauge
cnpg_pgbouncer_lists_dns_pending 0
# HELP cnpg_pgbouncer_lists_dns_queries Count of in-flight DNS queries.
# TYPE cnpg_pgbouncer_lists_dns_queries gauge
cnpg_pgbouncer_lists_dns_queries 0
# HELP cnpg_pgbouncer_lists_dns_zones Count of DNS zones in the cache.
# TYPE cnpg_pgbouncer_lists_dns_zones gauge
cnpg_pgbouncer_lists_dns_zones 0
# HELP cnpg_pgbouncer_lists_free_clients Count of free clients.
# TYPE cnpg_pgbouncer_lists_free_clients gauge
cnpg_pgbouncer_lists_free_clients 49
# HELP cnpg_pgbouncer_lists_free_servers Count of free servers.
# TYPE cnpg_pgbouncer_lists_free_servers gauge
cnpg_pgbouncer_lists_free_servers 0
# HELP cnpg_pgbouncer_lists_login_clients Count of clients in login state.
# TYPE cnpg_pgbouncer_lists_login_clients gauge
cnpg_pgbouncer_lists_login_clients 0
# HELP cnpg_pgbouncer_lists_pools Count of pools.
# TYPE cnpg_pgbouncer_lists_pools gauge
cnpg_pgbouncer_lists_pools 1
# HELP cnpg_pgbouncer_lists_used_clients Count of used clients.
# TYPE cnpg_pgbouncer_lists_used_clients gauge
cnpg_pgbouncer_lists_used_clients 1
# HELP cnpg_pgbouncer_lists_used_servers Count of used servers.
# TYPE cnpg_pgbouncer_lists_used_servers gauge
cnpg_pgbouncer_lists_used_servers 0
# HELP cnpg_pgbouncer_lists_users Count of users.
# TYPE cnpg_pgbouncer_lists_users gauge
cnpg_pgbouncer_lists_users 2
# HELP cnpg_pgbouncer_pools_cl_active Client connections that are linked to server connection and can process queries.
# TYPE cnpg_pgbouncer_pools_cl_active gauge
cnpg_pgbouncer_pools_cl_active{database="pgbouncer",user="pgbouncer"} 1
# HELP cnpg_pgbouncer_pools_cl_cancel_req Client connections that have not forwarded query cancellations to the server yet.
# TYPE cnpg_pgbouncer_pools_cl_cancel_req gauge
cnpg_pgbouncer_pools_cl_cancel_req{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_pools_cl_waiting Client connections that have sent queries but have not yet got a server connection.
# TYPE cnpg_pgbouncer_pools_cl_waiting gauge
cnpg_pgbouncer_pools_cl_waiting{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_pools_maxwait How long the first (oldest) client in the queue has waited, in seconds. If this starts increasing, then the current pool of servers does not handle requests quickly enough. The reason may be either an overloaded server or just too small of a pool_size setting.
# TYPE cnpg_pgbouncer_pools_maxwait gauge
cnpg_pgbouncer_pools_maxwait{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_pools_maxwait_us Microsecond part of the maximum waiting time.
# TYPE cnpg_pgbouncer_pools_maxwait_us gauge
cnpg_pgbouncer_pools_maxwait_us{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_pools_pool_mode The pooling mode in use. 1 for session, 2 for transaction, 3 for statement, -1 if unknown
# TYPE cnpg_pgbouncer_pools_pool_mode gauge
cnpg_pgbouncer_pools_pool_mode{database="pgbouncer",user="pgbouncer"} 3
# HELP cnpg_pgbouncer_pools_sv_active Server connections that are linked to a client.
# TYPE cnpg_pgbouncer_pools_sv_active gauge
cnpg_pgbouncer_pools_sv_active{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_pools_sv_idle Server connections that are unused and immediately usable for client queries.
# TYPE cnpg_pgbouncer_pools_sv_idle gauge
cnpg_pgbouncer_pools_sv_idle{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_pools_sv_login Server connections currently in the process of logging in.
# TYPE cnpg_pgbouncer_pools_sv_login gauge
cnpg_pgbouncer_pools_sv_login{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_pools_sv_tested Server connections that are currently running either server_reset_query or server_check_query.
# TYPE cnpg_pgbouncer_pools_sv_tested gauge
cnpg_pgbouncer_pools_sv_tested{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_pools_sv_used Server connections that have been idle for more than server_check_delay, so they need server_check_query to run on them before they can be used again.
# TYPE cnpg_pgbouncer_pools_sv_used gauge
cnpg_pgbouncer_pools_sv_used{database="pgbouncer",user="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_avg_query_count Average queries per second in last stat period.
# TYPE cnpg_pgbouncer_stats_avg_query_count gauge
cnpg_pgbouncer_stats_avg_query_count{database="pgbouncer"} 1
# HELP cnpg_pgbouncer_stats_avg_query_time Average query duration, in microseconds.
# TYPE cnpg_pgbouncer_stats_avg_query_time gauge
cnpg_pgbouncer_stats_avg_query_time{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_avg_recv Average received (from clients) bytes per second.
# TYPE cnpg_pgbouncer_stats_avg_recv gauge
cnpg_pgbouncer_stats_avg_recv{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_avg_sent Average sent (to clients) bytes per second.
# TYPE cnpg_pgbouncer_stats_avg_sent gauge
cnpg_pgbouncer_stats_avg_sent{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_avg_wait_time Time spent by clients waiting for a server, in microseconds (average per second).
# TYPE cnpg_pgbouncer_stats_avg_wait_time gauge
cnpg_pgbouncer_stats_avg_wait_time{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_avg_xact_count Average transactions per second in last stat period.
# TYPE cnpg_pgbouncer_stats_avg_xact_count gauge
cnpg_pgbouncer_stats_avg_xact_count{database="pgbouncer"} 1
# HELP cnpg_pgbouncer_stats_avg_xact_time Average transaction duration, in microseconds.
# TYPE cnpg_pgbouncer_stats_avg_xact_time gauge
cnpg_pgbouncer_stats_avg_xact_time{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_total_query_count Total number of SQL queries pooled by pgbouncer.
# TYPE cnpg_pgbouncer_stats_total_query_count gauge
cnpg_pgbouncer_stats_total_query_count{database="pgbouncer"} 3
# HELP cnpg_pgbouncer_stats_total_query_time Total number of microseconds spent by pgbouncer when actively connected to PostgreSQL, executing queries.
# TYPE cnpg_pgbouncer_stats_total_query_time gauge
cnpg_pgbouncer_stats_total_query_time{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_total_received Total volume in bytes of network traffic received by pgbouncer.
# TYPE cnpg_pgbouncer_stats_total_received gauge
cnpg_pgbouncer_stats_total_received{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_total_sent Total volume in bytes of network traffic sent by pgbouncer.
# TYPE cnpg_pgbouncer_stats_total_sent gauge
cnpg_pgbouncer_stats_total_sent{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_total_wait_time Time spent by clients waiting for a server, in microseconds.
# TYPE cnpg_pgbouncer_stats_total_wait_time gauge
cnpg_pgbouncer_stats_total_wait_time{database="pgbouncer"} 0
# HELP cnpg_pgbouncer_stats_total_xact_count Total number of SQL transactions pooled by pgbouncer.
# TYPE cnpg_pgbouncer_stats_total_xact_count gauge
cnpg_pgbouncer_stats_total_xact_count{database="pgbouncer"} 3
# HELP cnpg_pgbouncer_stats_total_xact_time Total number of microseconds spent by pgbouncer when connected to PostgreSQL in a transaction, either idle in transaction or executing queries.
# TYPE cnpg_pgbouncer_stats_total_xact_time gauge
cnpg_pgbouncer_stats_total_xact_time{database="pgbouncer"} 0
Clustersと同様に、特定のPoolerは、 Prometheus Operator's リソースPodMonitor を使用して監視できます。
Pooler
を正しく指すPodMonitor は、オペレーターがPooler
リソース自分自身で.spec.monitoring.enablePodMonitor をtrue
に設定することにより、自動的に作成できます(デフォルト:false)。
重要
自動的に作成された`PodMonitor` への変更は、次の調整サイクルでオペレーターによってオーバーライドされます。カスタマイズが必要な場合は、以下に説明するように行うことができます。
特定のプーラーのPodMonitor
を手動でデプロイするには、次のように定義し、必要に応じて変更します。
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: <POOLER_NAME>
spec:
selector:
matchLabels:
cnpg.io/poolerName: <POOLER_NAME>
podMetricsEndpoints:
- port: metrics
ロギング¶
ログは、次の例のように、JSON形式で標準出力に直接送信されます。
{
"level": "info",
"ts": SECONDS.MICROSECONDS,
"msg": "record",
"pipe": "stderr",
"record": {
"timestamp": "YYYY-MM-DD HH:MM:SS.MS UTC",
"pid": "<PID>",
"level": "LOG",
"msg": "kernel file descriptor limit: 1048576 (hard: 1048576); max_client_conn: 100, max expected fd use: 112"
}
}
接続の一時停止¶
Pooler 仕様により、宣言型構成のみを使用して、PgBouncerのPAUSE
およびRESUME コマンドを利用できます。デフォルトでfalse
に設定されるpaused オプションを介して。 true
に設定されている場合、オペレーターはPgBouncerでPAUSE
コマンドを内部的に呼び出します。
1.クエリが完了するのを待った後、PostgreSQLサーバーへのすべてのアクティブな接続を閉じます
2.クライアントからの新しい接続を一時停止します
paused オプションがfalse
に設定されると、オペレーターはPgBouncerでRESUME
コマンドを呼び出し、Pooler
で定義されたPostgreSQLサービスへのタップを再度開きます。
重要
将来のバージョンでは、スイッチオーバー操作はPgBouncerプーラーと完全に統合され、 PAUSE /RESUME 機能を利用してクライアントアプリケーションが知覚するダウンタイムを削減します。現時点では、 paused 属性を`true` に設定し、 :ref:``kubectl` に`cnpg` プラグインを使用する<kubectl に`cnpg` プラグインを使用する>` を介してスイッチオーバーコマンドを発行し、最後に paused 属性を`false` に復元することにより、同じ結果を達成できます。
制限事項¶
単一のPostgreSQLクラスター¶
プーラーの現在の実装は、特定のCloudNativePGクラスター(正確にはサービス)の一部として機能するように設計されています。現時点では、複数のクラスターにまたがるプーラーを作成することはできません。
制御された構成可能性¶
CloudNativePGは、PgBouncerレイヤーがPostgreSQLと通信するために使用されるいくつかの構成オプションを透過的に管理します。このようなオプションは外部から構成できず、TLS証明書、認証設定、databases
セクション、およびusers
セクションが含まれます。また、単一のPostgreSQLクラスターの特定のユースケースを考慮すると、採用された基準は、ユーザーが構成できるオプションを明示的にリストすることです。
注釈
採用されたソリューションがユースケースの大部分に対処しながら、PgBouncerがより高度でカスタマイズされたシナリオでガンマを完了するための別のオペレーターを将来的に実装する余地を残していると信じる理由があります。