コネクションプール
クエリエンジンは、データベース接続のコネクションプールを管理します。このプールは、Prisma Clientがデータベースへの最初の接続を開くときに作成され、これは次の2つの方法のいずれかで発生します
- `$connect()`を明示的に呼び出すか、あるいは
- 最初のクエリを実行することで、内部的に`$connect()`が呼び出される
リレーショナルデータベースコネクタはPrisma ORM独自のコネクションプールを使用し、MongoDBコネクタはMongoDBドライバーのコネクションプールを使用します。
v6.7.0以降、Prisma ORMには`queryCompiler`プレビュー機能が搭載されています。
有効にすると、Prisma ClientはRustベースのクエリエンジンバイナリなしで生成されます:
generator client {
provider = "prisma-client-js"
previewFeatures = ["queryCompiler", "driverAdapters"]
}
なお、`queryCompiler`とともにドライバーアダプターのプレビュー機能が必要です。`queryCompiler`プレビュー機能を使用する場合、コネクションプールは使用しているネイティブJSデータベースドライバーによって管理されます。
リレーショナルデータベース
リレーショナルデータベースコネクタはPrisma ORMのコネクションプールを使用します。コネクションプールには接続制限とプールタイムアウトがあり、これらは接続URLパラメータによって制御されます。
コネクションプールの仕組み
以下の手順は、クエリエンジンがコネクションプールをどのように使用するかを説明します。
- クエリエンジンは、設定可能なプールサイズとプールタイムアウトを持つコネクションプールをインスタンス化します。
- クエリエンジンは1つの接続を作成し、それをコネクションプールに追加します。
- クエリが来ると、クエリエンジンはプールから接続を予約してクエリを処理します。
- コネクションプール内にアイドル状態の接続がない場合、クエリエンジンは追加のデータベース接続を開き、データベース接続の数が`connection_limit`で定義された制限に達するまでコネクションプールに追加します。
- クエリエンジンがプールから接続を予約できない場合、クエリはメモリ内のFIFO(先入れ先出し)キューに追加されます。FIFOとは、クエリがキューに入った順序で処理されることを意味します。
- クエリエンジンがキュー内のクエリを時間制限前に処理できない場合、そのクエリに対してエラーコード`P2024`の例外をスローし、キュー内の次のクエリに移ります。
繰り返しプールタイムアウトエラーが発生する場合は、コネクションプールを最適化する必要があります。
コネクションプールサイズ
デフォルトのコネクションプールサイズ
デフォルトの接続数(プールサイズ)は、以下の計算式で算出されます。
num_physical_cpus * 2 + 1
`num_physical_cpus`は、アプリケーションが実行されているマシンの物理CPU数を表します。お使いのマシンに4つの物理CPUがある場合、コネクションプールには9つの接続が含まれます(`4 * 2 + 1 = 9`)。
この計算式は良い出発点となりますが、推奨される接続制限はデプロイのパラダイム、特にサーバーレスを使用しているかどうかに応じても変わります。
コネクションプールサイズの設定
データベース接続URLで`connection_limit`パラメータを明示的に設定することで、接続数を指定できます。例えば、Prismaスキーマの以下の`datasource`設定では、コネクションプールは正確に5つの接続を持つことになります
datasource db {
provider = "postgresql"
url = "postgresql://johndoe:mypassword@localhost:5432/mydb?connection_limit=5"
}
コネクションプールサイズの表示
Prisma Clientが使用する接続数は、ロギングとメトリクスを使用して表示できます。
`info` ロギングレベルを使用すると、Prisma Clientがインスタンス化されたときに開かれるコネクションプール内の接続数をログに記録できます。
例えば、以下のPrisma Clientインスタンスと呼び出しを考慮してください。
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient({
log: ['info'],
})
async function main() {
await prisma.user.findMany()
}
main()
prisma:info Starting a postgresql pool with 21 connections.
`PrismaClient`クラスがインスタンス化されたとき、ロギングにより、21個の接続を持つコネクションプールが開始されたことが`stdout`に通知されました。
`log: ['info']`によって生成される出力は、通知なしに任意のリリースで変更される可能性があることに注意してください。アプリケーションや構築中のツールでこの出力に依存している場合は、この点に留意してください。
コネクションプールのサイズや、使用中およびアイドル状態の接続数についてさらに詳しく知る必要がある場合は、メトリクス機能(現在プレビュー中)を使用できます。
以下の例を考慮してください。
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
await Promise.all([prisma.user.findMany(), prisma.post.findMany()])
const metrics = await prisma.$metrics.json()
console.dir(metrics, { depth: Infinity })
}
main()
{
"counters": [
// ...
{
"key": "prisma_pool_connections_open",
"labels": {},
"value": 2,
"description": "Number of currently open Pool Connections"
}
],
"gauges": [
// ...
{
"key": "prisma_pool_connections_busy",
"labels": {},
"value": 0,
"description": "Number of currently busy Pool Connections (executing a datasource query)"
},
{
"key": "prisma_pool_connections_idle",
"labels": {},
"value": 21,
"description": "Number of currently unused Pool Connections (waiting for the next datasource query to run)"
},
{
"key": "prisma_pool_connections_opened_total",
"labels": {},
"value": 2,
"description": "Total number of Pool Connections opened"
}
],
"histograms": [
/** ... **/
]
}
メトリクス出力で利用可能な詳細については、「メトリクスについて」セクションを参照してください。
コネクションプールタイムアウト
デフォルトのプールタイムアウト
デフォルトのコネクションプールタイムアウトは10秒です。この時間内にクエリエンジンがデータベースコネクションプールから接続を取得できない場合、例外をスローし、キュー内の次のクエリに移ります。
コネクションプールタイムアウトの設定
データベース接続URLで`pool_timeout`パラメータを明示的に設定することで、プールタイムアウトを指定できます。以下の例では、プールは`2`秒後にタイムアウトします。
datasource db {
provider = "postgresql"
url = "postgresql://johndoe:mypassword@localhost:5432/mydb?connection_limit=5&pool_timeout=2"
}
コネクションプールタイムアウトの無効化
`pool_timeout`パラメータを`0`に設定することで、コネクションプールタイムアウトを無効にできます。
datasource db {
provider = "postgresql"
url = "postgresql://johndoe:mypassword@localhost:5432/mydb?connection_limit=5&pool_timeout=0"
}
クエリがキューに留まる必要がある場合(例えば、大量のレコードを並行してインポートしており、ジョブが完了するまでにキューが利用可能なRAMをすべて使い果たすことがないという確信がある場合など)、コネクションプールタイムアウトを無効にすることを選択できます。
MongoDB
MongoDBコネクタはPrisma ORMのコネクションプールを使用しません。コネクションプールはMongoDBドライバーによって内部的に管理され、接続文字列パラメータを介して設定されます。
外部コネクションプーラー
基盤となるデータベースがサポートできる範囲を超えて`connection_limit`を増やすことはできません。これはサーバーレス環境で特に課題となります。そこでは各関数が`PrismaClient`のインスタンス、つまり独自のコネクションプールを管理するためです。
アプリケーションや関数がデータベース接続制限を使い果たすのを防ぐため、PgBouncerのような外部コネクションプーラーの導入を検討してください。
手動でのデータベース接続処理
Prisma ORMを使用する場合、データベース接続はエンジンレベルで処理されます。つまり、開発者には公開されず、手動でアクセスすることはできません。