pg gem を介して PostgreSQL に対応しています。
このガイドでは、新しい Rails アプリを作成し、証明書検証付きの TLS で ClickHouse Managed Postgres に接続したうえで、移行を実行し、スキャフォールドで生成した Post リソースを配信します。
前提条件
- Ruby 3.2 以降。本ガイドは Ruby 4.0.7、Rails 8.1.4、
pg1.6.3 で動作確認しています。 - ClickHouse Cloud アカウント
pg gem には、libpq を同梱した Linux、macOS、Windows 向けのプリコンパイル済みビルドが用意されているため、ローカル環境に PostgreSQL をインストールする必要はありません。
ClickHouse Managed Postgres サービスを作成する
ClickHouse Cloud コンソールで New service をクリックし、Postgres を選択します。インスタンスは数分で利用可能になります。詳しい手順については、クイックスタートを参照してください。接続情報を取得する
サービスを開き、左サイドバーの Connect をクリックします。Directly を選択したまま、Use SSL をオンにします。 パスワードとサーバーのホスト名をコピーしてから、Download CA certificate をクリックします。 CA 証明書はサービスごとに固有です。後から Settings → CA Certificate でダウンロードすることもできます。 直接接続か PgBouncer か? Rails サーバーは長時間稼働するプロセスであり、独自の接続プール (config/database.yml の max_connections。デフォルトではプロセスあたり 5) を保持します。そのため、このガイドではポート 5432 で Postgres に直接接続します。
多数のプロセスを実行していて接続数の上限に達する場合は、PgBouncer の使用を参照してください。
Rails アプリを作成する
Rails をインストールし、PostgreSQL を使用するアプリを作成します。データベース接続を設定する
ダウンロードした CA 証明書をアプリのconfig ディレクトリに移動し、ca-certificate.pem にリネームします。
ダウンロードしたファイルには、your-service-ca-certificate.pem のように、サービス名に基づいた名前が付いています:
config/database.yml の development セクションを、次の内容に置き換えてください。
sslmode: verify-full を指定すると、libpq はサーバー証明書がサービスの CA によって署名されていること、および証明書がホスト名と一致することを検証します。Rails.root.join は絶対パスを返すため、どのディレクトリから Rails を起動してもこの設定は正しく機能します。
DATABASE_URL にサービスの接続先を設定します。その際、データベース名には新しい名前を指定してください。このガイドでは guide_rails を使用します:
DATABASE_URL にはクエリ文字列を付けないでください。URL に含まれるパラメータは database.yml のキーよりも優先されるため、sslrootcert=your-service-ca-certificate.pem をそのままコピーしてしまうと、設定した値が現在のディレクトリを基準とした相対パスで置き換えられてしまいます。db:create が作成するのは、DATABASE_URL で指定されたデータベースのみです。CREATE DATABASE を実行する際にはデフォルトの postgres データベースに接続しますが、このデータベース自体には変更を加えません。また、DATABASE_URL が設定されている場合、Rails はローカルのテスト用データベースを作成しません。
モデルを生成して移行を実行する
Post リソースのスキャフォールドを生成し、その移行を適用します。既存のアプリケーションの場合、bin/rails db:migrate を実行すると、アプリケーションの既存のテーブルも新しいデータベースに作成されます。SQLite のデータはコピーされないため、これらのテーブルは空の状態で作成されます。
データベースにクエリを実行する
Active Record の呼び出しをいくつか記述したscript/posts_demo.rb を作成します。
bin/rails runner で実行します:
pg_stat_ssl を参照し、session が暗号化されていることを確認しています。
アプリを実行する
開発サーバーを起動します。guide_rails データベースを展開して posts テーブルを選択します。
Rails は、移行を追跡するための schema_migrations と ar_internal_metadata も作成します。
posts テーブルには、script/posts_demo.rb で作成された 2 行が格納されています。
PgBouncer の使用
各 Rails プロセスは最大max_connections 個の直接接続を開きます。多数のプロセスの接続数の合計が Postgres の接続上限に近づく場合は、代わりに同梱の PgBouncer を経由して接続してください。Connect モーダルで via PgBouncer を選択し、DATABASE_URL でポート 6432 を指定します。
PgBouncer はトランザクションプーリングモードで動作します。
-
プリペアドステートメントは、
pggem が 1.6 以降で、かつlibpq17 以降を使用していれば、Rails のデフォルト設定のまま動作します。プリコンパイル済みのpg1.6 gem にはlibpq18 が同梱されています。これらのバージョンでは、Rails がキャッシュからステートメントを破棄する際にプロトコルレベルのCloseメッセージで解放し、同梱の PgBouncer がこれを処理します。それより古いpgやlibpqでは代わりに SQL のDEALLOCATEが送信されるため、PgBouncer 経由ではprepared statement "a1" does not existというエラーで失敗します。これがトランザクション内で発生すると、そのトランザクションは中断されます (PG::InFailedSqlTransaction)。バージョンを確認するには、次のコマンドを実行します。それぞれ1.6.0以降、170000以降である必要があります。アップグレードできない場合は、developmentセクションにprepared_statements: falseを追加してください。Rails はproductionではプリペアドステートメントを有効にしますが、developmentではquery_log_tags_enabledが有効なため、デフォルトで無効になっています。 -
移行では、同時実行を防ぐためにセッションレベルのアドバイザリロック (
pg_try_advisory_lock) が取得されます。トランザクションプーリングでは、ロック解除の要求が別の Postgres 接続に届くことがあり、その場合はFailed to release advisory lockで失敗してロックが保持されたままになります。その結果、以降の実行はCannot run migrations because another migration process is currently runningで失敗します。ポート5432の直接接続用DATABASE_URLを指定してbin/rails db:migrateを実行するか、次のようにロックを無効にしてください。
advisory_locks: false を設定する場合は、移行を同時に実行するデプロイが 1 つだけになるようにしてください。
トラブルシューティング
SSL error: certificate verify failed:sslrootcertがサービスの CA 証明書を指していません。Settings → CA Certificate から証明書を再度ダウンロードしてください。CA はサービスごとに異なるため、公開 CA バンドルは使用できません。root certificate file "..." does not exist:sslrootcertに指定したパスが正しくありません。config/ca-certificate.pemが存在するか確認してください。
次のステップ
production設定でも、同じsslmodeとsslrootcertの設定を使用してください。- 接続: 接続文字列、PgBouncer、TLS について説明します。
- 設定:
max_connectionsなど、Postgres と PgBouncer のパラメータを変更します。 - 読み取りレプリカ: 読み取り処理をスケールさせます。たとえば、Rails の複数データベース機能と組み合わせて利用できます。
- Sync to ClickHouse: Rails のテーブルを ClickHouse にレプリケートし、分析に活用します。