接続プール
クエリエンジンは、データベース接続の接続プールを管理します。プールは、Prisma Clientがデータベースへの最初の接続を開くときに作成されます。これは、次の2つの方法のいずれかで発生する可能性があります。
- 明示的に
$connect()
を呼び出す または - 最初のクエリを実行することによって。これは、内部で
$connect()
を呼び出します。
リレーショナルデータベースコネクタはPrisma ORM独自の接続プールを使用し、MongoDBコネクタはMongoDBドライバ接続プールを使用します。
リレーショナルデータベース
リレーショナルデータベースコネクタは、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
クラスがインスタンス化されると、ロギングはstdout
に21個の接続を持つ接続プールが開始されたことを通知しました。
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を使用する場合、データベース接続はエンジンレベルで処理されます。これは、開発者に公開されず、手動でアクセスすることができないことを意味します。