連線池
查詢引擎管理著一個數據庫連線的連線池。該連線池在 Prisma Client 開啟與資料庫的第一個連線時建立,這可以透過以下兩種方式之一發生
- 透過顯式呼叫
$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 引數控制。
連線池的工作原理
以下步驟描述了查詢引擎如何使用連線池
- 查詢引擎例項化一個連線池,該連線池具有可配置的池大小和池超時。
- 查詢引擎建立一個連線並將其新增到連線池中。
- 當有查詢傳入時,查詢引擎從連線池中保留一個連線來處理查詢。
- 如果連線池中沒有空閒連線可用,查詢引擎將開啟額外的資料庫連線並將其新增到連線池中,直到資料庫連線數達到
connection_limit定義的限制。 - 如果查詢引擎無法從連線池中保留連線,查詢將按 FIFO(先進先出)順序新增到記憶體佇列中。FIFO 意味著查詢按照它們進入佇列的順序進行處理。
- 如果查詢引擎在時間限制之前無法處理佇列中的某個查詢,它將針對該查詢丟擲錯誤程式碼為
P2024的異常,並轉到佇列中的下一個查詢。
如果你持續遇到連線池超時錯誤,你需要最佳化連線池。
連線池大小
預設連線池大小
預設連線數(池大小)按以下公式計算
num_physical_cpus * 2 + 1
num_physical_cpus 表示你的應用程式執行機器上的物理 CPU 數量。如果你的機器有四個物理 CPU,你的連線池將包含九個連線(4 * 2 + 1 = 9)。
儘管該公式是一個很好的起點,但推薦的連線限制也取決於你的部署正規化——特別是如果你正在使用無伺服器環境。
設定連線池大小
你可以透過在資料庫連線 URL 中顯式設定 connection_limit 引數來指定連線數。例如,在你的 Prisma schema 中使用以下 datasource 配置,連線池將恰好有五個連線
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 時,資料庫連線在引擎層面進行處理。這意味著它們不向開發者暴露,也無法手動訪問它們。