Connection Pooling

CloudNativePGは、 Pooler CRDを介して、 PostgreSQLで最も人気のあるオープンソース接続プーラーの1つである PgBouncerIntegrationStatus とのコネクションプーリングのネイティブサポートを提供します。

一言で言えば、CloudNativePGの Pooler は、アプリケーションとPostgreSQLサービス(例 rw サービス)の間にあるPgBouncerポッドのデプロイであり、個別のスケーラビリティで構成可能な可用性の高い データベースアクセスレイヤー を作成します。

アーキテクチャ

次の図は、PgBouncerに基づくデータベースアクセスレイヤーの序文が、スイスアーミーナイフの追加ブレードのように、CloudNativePGのアーキテクチャをどのように変えるかを強調しています。 PostgreSQLプライマリサービスに直接接続する代わりに、アプリケーションはPgBouncerの同等のサービスに接続できるようになり、既存の接続を再利用して、 PostgreSQL側のパフォーマンスとリソース管理を改善できます。

Applications writing to the single primary via PgBouncer

Applications writing to the single primary via PgBouncer

クイックスタート

CloudNativePGがPgBouncerpoolerを実装する方法を説明する最も簡単な方法は、例を使用することです。

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"

重要

プーラー名前は、同じネームスペース内のクラスター名前と決してマッチしてはなりません。

これにより、 cluster-example というPostgres Cluster リソースと厳密に関連付けられ、read / writeservice( rw 、したがって cluster-example-rw )によって識別されるプライマリを指す、 pooler-example-rw (isarbitraryという名前)という新しい Pooler リソースが作成されます。

Pooler は、 Postgresクラスターの同じネームスペースに存在する必要がありデフォルトプールサイズで実行され、それぞれ最大1000接続を受け入れるPostgreSQLを実行する3つのポッドのKubernetesデプロイメントで構成されデータベース。 。

重要

Pooler はPgBouncerの * フォールバックデータベースのみを設定します。つまり、クライアントから渡された接続文字列のすべてのパラメーターがPostgreSQLサーバーに中継されます(["Section [databases]" in PgBouncer's documentation](https://www.pgbouncer.org/config.html#section-databases)を参照してください)。

さらに、CloudNativePGは、PgBouncerで使用される構成ファイルを含むプーラーと同じ名前のシークレットを自動的に作成します。

プーラーリソースのライフサイクル

Pooler リソースは Cluster 管理のリソースではありません。プーラーは、必要なときに手動で作成することになっています。さらに、 PostgreSQLクラスターごとに複数のプーラーをデプロイできます。

ノート重要なことは、 Cluster およびthe Pooler リソースのライフサイクルは現在独立していることです。 Cluster の削除は Pooler の自動削除を意味せず、その逆も同様です。

重要

Pooler の仕組みがわかったので、可能なアーキテクチャに関して完全に自由になりました:プーラーのないクラスター、単一のプーラーのクラスター、または複数のプーラーのクラスター(つまり、アプリケーションごとに1つ)を持つことができます。

セキュリティ

PgBouncerプーラーはCloudNativePGサポートと透過的に統合され、プールのクライアント(アプリケーション)側とサーバー( PostgreSQL )側の両方で TLS接続 による転送中の暗号化をサポートしプール。

具体的には、PgBouncerはPostgreSQLサーバーの証明書を自動的に再利用します。さらに、TLSクライアント証明書認証を使用してPostgreSQLサーバーに接続し、クライアントのパスワード認証のために auth_query を実行します(以下の 認証を使用する を参照)。

コンテナは pgbouncer システムユーザとして実行され、 pgbouncer データベースへのアクセスは、ローカル接続を介して、 peer 認証を通じてのみ許可されます。

証明書

デフォルトでは、PgBouncerプーラーはクラスター自分自身が使用するものと同じ証明書を使用しますが、ユーザがそれらの証明書を提供する場合、プーラーは次のフォーマットのシークレットを受け入れます。

1.基本認証2。 TLS3。不透明

Opaqueの場合、使用するニーズがある特定のキーを探します。これらのキーは次のとおりです。

  • tls.crt

  • tls。キー

したがって、このシークレットをTLSシークレットとして扱い、そこからスタートことができます。

認証

パスワードベースの認証 は、CloudNativePGのPgBouncerのクライアントでサポートされている唯一のメソッドです。

内部的には、実装はPgBouncerの auth_user および auth_query オプションに依存しています。具体的には、演算子:

PostgreSQLサーバーに cnpg_pooler_pgbouncer という標準ユーザを作成します - postgres データベースにルックアップファンクションを作成し、実行を許可します cnpg_pooler_pgbouncer ユーザ(PoLA)に対する特権 - このユーザのTLS証明書を発行します - cnpg_pooler_pgbouncer を auth_user として設定します - 認証にTLS証明書を使用するようにPgBouncerを構成します PostgreSQLサーバーに対する cnpg_pooler_pgbouncer - クラスターにないことを検出すると、上記のすべてを削除します 関連付けられているプーラー

重要

独自のシークレットを指定した場合、演算子はプーラーを自動的に統合しません。

プーラーを手動で統合するには、独自のシークレットを指定した場合、クラスター内から次のクエリを実行する必要があります。

1.ロールを作成します。

GRANT CONNECT ON DATABASE { database name here } TO cnpg_pooler_pgbouncer;
GRANT CONNECT ON DATABASE { database name here } TO cnpg_pooler_pgbouncer;

2.アプリケーションデータベースごとに、 cnpg_pooler_pgbouncer に接続するパーミッションを付与します。

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"
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"

3.各アプリケーションデータベースに接続し、各アプリケーションデータベース内に認証ファンクションを作成します。

edb_notranlate_5 sql CREATE OR REPLACE関数user_search(uname TEXT)RETURNS TABLE(usename 名前、passwd text)as ‘SELECT usename、passwd FROM pg_shadow WHERE usename = $ 1;’ LANGUAGE SQL SECURITY DEFINER;

すべての関数の取り消しuser_search(text)FROM public;

cnpg_pooler_pgbouncerへの関数user_search(text)に対するEXECUTEの付与。 console kubectl exec -ti <PGBOUNCER_POD> -- curl 127.0.0.1:9127/metrics

PodTemplates

Pooler リソースの template セクションでポッドテンプレートの仕様を利用できます。詳細については、 APIリファレンスの`PoolerSpec section <api_reference.md#PoolerSpec>`__を参照してください。

テンプレートを使用して、ポッドとノードのアフィニティおよびアンチアフィニティルールの詳細な制御を含め、必要に応じてポッドを設定できます。デフォルトでは、コンテナは ghcr.io/cloudnative-pg/pgbouncer のイメージを使用します。

PodAntiAffinityを指定するPoolerの例:

#  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

注釈

.spec.template.spec.containers は、 PodSpec の必須フィールドであるため、変更しない場合は明示的に [] に設定する必要があります。 .spec.template.spec.containers が設定されていない場合、マニフェストを適用しようとするとkubernetes APIサーバーは次のエラーを結果ます: error validating "pooler.yaml": error validating data: ValidationError(Pooler.spec.template.spec): missing required field "containers"

ここで、リソースを設定し、使用するイメージを変更する例:

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: <POOLER_NAME>
spec:
  selector:
    matchLabels:
      cnpg.io/poolerName: <POOLER_NAME>
  podMetricsEndpoints:
  - port: metrics

高可用性(HA)

Kubernetesの展開のおかげで、単一のインスタンスまたはマルチプルのポッドで実行するようにプーラーを構成できます。公開されたサービスにより、クライアントはPgBouncerを実行している利用可能なポッドにランダムに分散されます-これにより、基盤となるサーバー( rw サービスを使用する場合)またはサーバー(マルチプルのレプリカで ro サービスを使用する場合)への接続を自動的に管理および再利用します。

警告

インフラストラクチャがマルチプルのアベイラビリティゾーンにまたがっており、それらのレイテンシが高い場合は、ネットワークホップに注意してください。例、ゾーン2で実行されているアプリケーションが、ゾーン3で実行されているPgBouncerに接続し、ゾーン1のPostgreSQLプライマリを指している場合を考えます。

PgBouncer設定オプション

演算子は configuration options for PgBouncer のほとんどを管理し、それらのサブセットのみを変更できます。

警告

演算子がオプションを検証しないため、各オプションの値を正しく設定する必要があります。

以下に、カスタマイズできるPgBouncerオプションのリストがあります。それらのそれぞれには、その特定のパラメータのPgBouncer文書へのリンクが含まれています。ここで特に明記しない限り、デフォルト値はPgBouncerによって直接設定されたものです:

に追加される-CNPで必要

統計がPrometheusによって既に収集されている場合、無効( 0 ) 以下の MonitoringConfiguration セクションで説明されているエクスポート

PgBouncer構成のカスタマイズは、 .spec.pgbouncer.parameters マップに宣言的に記述されます。

演算子はPooler仕様の変更に反応し、すべてのPgBouncerインスタンスがサービスを中断することなく更新された構成をリロードします。

警告

すべてのPgBouncerポッドは、仕様のパラメーターに合わせて同じ構成になります。これらのパラメーターに誤りがあると、全体Pooler **の操作性が混乱する可能性があります。演算子は、**オプションの値を検証しません。

監視

Pooler のPgBouncer実装にはdefaultPrometheusエクスポーターが付属しており、次を実行することにより、 cnpg_pgbouncer_ プレフィックスを持つ複数のメトリックを自動的に使用可能にします。

  • SHOW LISTS (プレフィックス: cnpg_pgbouncer_lists )

  • SHOW POOLS (プレフィックス: cnpg_pgbouncer_pools )

  • SHOW STATS (プレフィックス: cnpg_pgbouncer_stats )

CloudNativePGインスタンスと同様に、エクスポーターはPgBouncerを実行している各ポッドのport 9127 で実行され、Goランタイムに関連するメトリック(プレフィックス go_* を含む)も提供します。次のコマンドを使用して、PgBouncerを実行しているポッドでエクスポーターをデバッグできます。

{
  "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"
  }
}

cnpg_pgbouncer メトリックの出力の例:

edb_notranlate_10

Clusters と同様に、 プロメテウス演算子の例 を使用している場合は、次の PodMonitor を定義することにより、特定のプーラーをスクレイピングするように構成できます。

edb_notranlate_11

ロギング

ログは、次の例のように、 JSONフォーマットで標準出力に直接送信されます。

edb_notranlate_12

接続の一時停止

Pooler 仕様では、宣言構成のみを使用して、デフォルトで false に設定された paused オプションを介して、PgBouncerの PAUSE および RESUME コマンドを利用できます。 true に設定すると、演算子はPgBouncerで PAUSE コマンドを内部的に呼び出します。

1.クエリの完了を待った後、 PostgreSQLサーバーへのすべてのアクティブな接続を閉じます2。クライアントからの新しい接続を一時停止します

paused オプションを false に戻すと、演算子はPgBouncerで RESUME コマンドを呼び出し、 Pooler で定義されたPostgreSQLserviceに向けてタップを再度開きます。

重要

将来のバージョンでは、スイッチオーバーオペレーションはPgBouncerプーラーと完全に統合され、 PAUSE / RESUME 機能を利用して、クライアントアプリケーションが感知するダウンタイムを削減します。現時点では、 paused 属性を true に設定し、 cnpg を介してスイッチオーバーコマンドを発行し、最終的に paused 属性を false に復元することで、同じ結果を得ることができます。

制限

単一のPostgreSQLクラスター

プーラーの現在の実装は、特定のCloudNativePGクラスター(正確にはサービス)のパートとして機能するように設計されています。現時点では、マルチプルのクラスターにまたがるプーラーを作成することはできません。

制御された構成可能性

CloudNativePGは、PgBouncerレイヤーがPostgreSQLと通信するために使用されるいくつかの構成オプションを透過的に管理します。そのようなオプションは、外部から構成できず、TLS証明書、認証設定、 databases セクション、および users セクションが含まれます。また、単一のPostgreSQLクラスターの特定のユースケースを考慮すると、採用される基準は、ユーザーが構成できるオプションを明示的にリストすることです。

注釈

採用されたソリューションは、ユースケースの大部分に対応しているが、PgBouncerの別の演算子を将来実装して、より高度でカスタマイズされたシナリオでガンマを完成させる余地があると信じる理由があります。