資料庫連線
資料庫可以處理的併發連線數是有限的。每個連線都需要佔用 RAM,這意味著僅僅增加資料庫連線限制而不擴充套件可用資源
- ✔ 可能會允許更多程序連線,但是
- ✘ 會嚴重影響**資料庫效能**,並可能導致資料庫因記憶體不足錯誤而**關閉**
您的應用程式**管理連線**的方式也會影響效能。本指南介紹如何在無伺服器環境和長期執行的程序中處理連線管理。
本指南重點介紹**關係型資料庫**以及如何配置和調優 Prisma ORM 連線池(MongoDB 使用 MongoDB 驅動程式連線池)。
長期執行的程序
長期執行的程序示例包括託管在 Heroku 等服務或虛擬機器上的 Node.js 應用程式。請使用以下清單作為長期執行環境中連線管理的指南
建議的連線池大小
對於長期執行的程序,開始時建議的連線池大小 (connection_limit) 為**預設池大小** (num_physical_cpus * 2 + 1) ÷ **應用程式例項數**。
num_physical_cpus 指的是您的應用程式執行所在的機器的 CPU 數量。
如果您有**一個**應用程式例項
- 預設連線池大小預設適用 (
num_physical_cpus * 2 + 1) - 您無需設定connection_limit引數。 - 您可以選擇性地調優連線池大小。
如果您有**多個**應用程式例項
- 您必須**手動**設定
connection_limit引數。例如,如果您的計算池大小為 10 並且您有 2 個應用程式例項,則connection_limit引數應**不超過 5**。 - 您可以選擇性地調優連線池大小。
長期執行應用程式中的 PrismaClient
在**長期執行**的應用程式中,我們建議您
- ✔ 建立
PrismaClient的**一個**例項並在您的應用程式中重複使用 - ✔ 僅在開發環境中將
PrismaClient分配給全域性變數,以防止熱過載建立新例項
重複使用單個 PrismaClient 例項
要重複使用單個例項,請建立一個匯出 PrismaClient 物件的模組
import { PrismaClient } from '@prisma/client'
let prisma = new PrismaClient()
export default prisma
該物件在模組首次匯入時被快取。後續請求將返回快取的物件,而不是建立新的 PrismaClient
import prisma from './client'
async function main() {
const allUsers = await prisma.user.findMany()
}
main()
您不必完全複製上述示例——目標是確保 PrismaClient 被快取。例如,您可以在context 物件中例項化 PrismaClient,然後將其傳入 Express 應用程式。
不要顯式呼叫 $disconnect()
在持續提供請求的長期執行應用程式中,您不需要顯式呼叫 $disconnect()。每次查詢後斷開連線會花費時間,並可能降低您的應用程式速度。
防止熱過載建立 PrismaClient 的新例項
像 Next.js 等框架支援更改檔案的熱過載,這使您無需重啟即可檢視應用程式的更改。但是,如果框架重新整理負責匯出 PrismaClient 的模組,這可能導致在**開發環境中出現額外的、不必要的 PrismaClient 例項**。
作為一種變通方法,您可以將 PrismaClient 僅作為開發環境中的全域性變數儲存,因為全域性變數不會被重新載入
import { PrismaClient } from '@prisma/client'
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }
export const prisma =
globalForPrisma.prisma || new PrismaClient()
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
您匯入和使用 Prisma Client 的方式不會改變
import { prisma } from './client'
async function main() {
const allUsers = await prisma.user.findMany()
}
main()
每個 CLI 命令建立的連線數
在對 Postgres、MySQL 和 SQLite 進行的本地測試中,每個 Prisma CLI 命令通常使用單個連線。下表顯示了這些測試中觀察到的範圍。您的環境可能會產生略微不同的結果。
| 命令 | 連線數 | 描述 |
|---|---|---|
migrate status | 1 | 檢查遷移狀態 |
migrate dev | 1–4 | 在開發環境中應用待處理的遷移 |
migrate diff | 1–2 | 將資料庫 schema 與遷移歷史進行比較 |
migrate reset | 1–2 | 重置資料庫並重新應用遷移 |
migrate deploy | 1–2 | 在生產環境中應用待處理的遷移 |
db pull | 1 | 將資料庫 schema 拉取到 Prisma schema 中 |
db push | 1–2 | 將 Prisma schema 推送到資料庫 |
db execute | 1 | 執行原始 SQL 命令 |
db seed | 1 | 使用初始資料填充資料庫 |
無伺服器環境 (FaaS)
無伺服器環境的示例包括託管在 AWS Lambda、Vercel 或 Netlify Functions 上的 Node.js 函式。請使用以下清單作為無伺服器環境中連線管理的指南
- 熟悉無伺服器連線管理挑戰
- 根據您是否有外部連線池器設定連線池大小 (
connection_limit),並可選擇性地調優連線池大小 - 在處理程式外部例項化
PrismaClient,並且不要顯式呼叫$disconnect() - 配置函式併發並處理空閒連線
無伺服器挑戰
在無伺服器環境中,每個函式都會建立 PrismaClient 的**自己的例項**,並且每個客戶端例項都有自己的連線池。
考慮以下示例,其中單個 AWS Lambda 函式使用 PrismaClient 連線到資料庫。connection_limit 為 3

流量高峰導致 AWS Lambda 額外生成兩個 Lambda 函式來處理增加的負載。每個 Lambda 函式都會建立一個 PrismaClient 例項,每個例項的 connection_limit 都為 3,這導致最多連線到資料庫 9 個連線

200 個併發函式(因此可能有 600 個連線)響應流量高峰 📈 可以非常迅速地耗盡資料庫連線限制。此外,任何處於**暫停**狀態的函式預設會保持其連線開啟,並阻止它們被其他函式使用。
- 首先將
connection_limit設定為1 - 如果較小的連線池大小不足,請考慮使用外部連線池器,例如 PgBouncer
建議的連線池大小
無伺服器環境中建議的連線池大小 (connection_limit) 取決於
沒有外部連線池器
如果您**沒有**使用外部連線池器,首先將連線池大小 (connection_limit) 設定為 1,然後進行最佳化。每個傳入請求都會啟動一個短生命週期的 Node.js 程序,在流量高峰期間,許多具有高 connection_limit 的併發函式會迅速**耗盡資料庫連線限制**。
以下示例演示瞭如何在連線 URL 中將 connection_limit 設定為 1
- PostgreSQL
- MySQL
postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public&connection_limit=1
mysql://USER:PASSWORD@HOST:PORT/DATABASE?connection_limit=1
如果您正在使用 AWS Lambda 並且沒有配置 connection_limit,請參閱以下 GitHub 問題以獲取有關預期預設連線池大小的資訊:https://github.com/prisma/docs/issues/667
使用外部連線池器
如果您正在使用外部連線池器,請使用預設連線池大小 (num_physical_cpus * 2 + 1) 作為起點,然後調優連線池大小。外部連線池器應能防止流量高峰使資料庫超負荷。
最佳化並行請求
如果 connection_limit 為 1,此函式將被迫**序列**(一個接一個)傳送查詢,而不是**並行**。這會降低函式處理請求的能力,並可能導致連線池超時錯誤。調整 connection_limit 引數,直到流量高峰
Promise.all() {
query1,
query2,
query3
query4,
...
}
不會耗盡資料庫連線限制
- 不會導致連線池超時錯誤
- 無伺服器環境中的
PrismaClient
在處理程式外部例項化 PrismaClient
在函式處理程式範圍之外例項化 PrismaClient 以增加重用的機會。只要處理程式保持“熱”(在使用中),連線就可能被重用
不要顯式呼叫 $disconnect()
import { PrismaClient } from '@prisma/client'
const client = new PrismaClient()
export async function handler() {
/* ... */
}
您不需要在函式結束時顯式呼叫 $disconnect(),因為容器可能被重用。開啟新連線會花費時間,並降低您的函式處理請求的能力。
其他無伺服器注意事項
容器重用
無法保證後續的函式呼叫會命中同一個容器——例如,AWS 可以隨時選擇建立一個新容器。
程式碼應假定容器是無狀態的,並且僅在連線不存在時才建立連線——Prisma Client JS 已經實現了此邏輯。
殭屍連線
被標記為“待移除”且未被重用的容器仍然會**保持連線開啟**,並可能在該狀態下停留一段時間(AWS 未知且未記錄)。這可能導致資料庫連線的次優利用。
一個潛在的解決方案是**清理空閒連線**(serverless-mysql 實現了這個想法,但不能與 Prisma ORM 一起使用)。
併發限制
根據您的無伺服器併發限制(並行執行的無伺服器函式數量),您可能仍然會耗盡資料庫的連線限制。當過多函式併發呼叫,每個函式都有自己的連線池時,就可能發生這種情況,最終耗盡資料庫連線限制。為防止這種情況,您可以將您的無伺服器併發限制 設定為低於資料庫最大連線限制除以每個函式呼叫使用的連線數(因為您可能希望能夠從其他客戶端連線以用於其他目的)的值。
最佳化連線池
如果查詢引擎無法在時間限制之前處理佇列中的查詢,您將在日誌中看到連線池超時異常。連線池超時可能發生在以下情況:
許多使用者同時訪問您的應用程式
- 您並行傳送大量查詢(例如,使用
await Promise.all()) - 如果在配置了建議的連線池大小後仍然持續遇到連線池超時,您可以進一步調優
connection_limit和pool_timeout引數。
增加連線池大小
注意
queryCompiler 預覽功能。啟用後,您的 Prisma Client 將不帶基於 Rust 的查詢引擎二進位制檔案生成
請注意,queryCompiler 需要同時啟用驅動介面卡預覽功能。使用 queryCompiler 預覽功能時,連線池大小透過您正在使用的原生 JS 驅動程式設定。:
generator client {
provider = "prisma-client-js"
previewFeatures = ["queryCompiler", "driverAdapters"]
}
增加連線池大小允許查詢引擎並行處理更多的查詢。請注意,您的資料庫必須能夠支援增加的併發連線數,否則您將**耗盡資料庫連線限制**。
要增加連線池大小,請手動將 connection_limit 設定為更高的數字
注意:在無伺服器環境中將 connection_limit 設定為 1 是一個建議的起點,但此值也可以進行調優。
datasource db {
provider = "postgresql"
url = "postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public&connection_limit=40"
}
增加連線池超時時間
增加連線池超時時間可以給查詢引擎更多時間來處理佇列中的查詢。您可以在以下場景中考慮這種方法:
您已經增加了 connection_limit。
- 您確信佇列不會增長超過某個大小,否則**您最終會耗盡 RAM**。
- 要增加連線池超時時間,請將
pool_timeout引數設定為大於預設值(10 秒)的值
停用連線池超時
datasource db {
provider = "postgresql"
url = "postgresql://johndoe:mypassword@localhost:5432/mydb?connection_limit=5&pool_timeout=20"
}
停用連線池超時可以防止查詢引擎在等待連線 x 秒後丟擲異常,並允許佇列累積。您可以在以下場景中考慮這種方法:
您在有限的時間內提交大量查詢——例如,作為匯入或更新資料庫中所有客戶的任務的一部分。
- 要停用連線池超時,請將
pool_timeout引數設定為0 - 您確信佇列不會增長超過某個大小,否則**您最終會耗盡 RAM**。
- 要增加連線池超時時間,請將
pool_timeout引數設定為大於預設值(10 秒)的值
外部連線池器
datasource db {
provider = "postgresql"
url = "postgresql://johndoe:mypassword@localhost:5432/mydb?connection_limit=5&pool_timeout=0"
}
像 Prisma Accelerate 和 PgBouncer 這樣的連線池器可以防止您的應用程式耗盡資料庫的連線限制。
如果您希望使用 Prisma CLI 對資料庫執行其他操作,例如遷移和內省,您需要新增一個環境變數,在您的 Prisma schema 的 datasource.directUrl 屬性中提供對資料庫的直接連線
.env
schema.prisma 以使用新的直接 URL# Connection URL to your database using PgBouncer.
DATABASE_URL="postgres://root:password@127.0.0.1:54321/postgres?pgbouncer=true"
# Direct connection URL to the database used for migrations
DIRECT_URL="postgres://root:password@127.0.0.1:5432/postgres"
schema.prisma
directUrl 欄位的更多資訊,請參閱此處。datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
Prisma Accelerate
Prisma Accelerate 是 Prisma 構建的一個託管式外部連線池器,它整合在 Prisma Data Platform 中,併為您處理連線池。
PgBouncer
PostgreSQL 只支援一定數量的併發連線,當服務使用量增加時,這個限制很快就會達到——尤其是在無伺服器環境中。
PgBouncer 維護一個到資料庫的連線池,並透過位於 Prisma Client 和資料庫之間來代理傳入的客戶端連線。這減少了資料庫在任何給定時間必須處理的程序數量。PgBouncer 將有限數量的連線傳遞給資料庫,並在連線可用時將額外連線排隊等待傳遞。要使用 PgBouncer,請參閱使用 PgBouncer 配置 Prisma Client。
AWS RDS Proxy
由於 AWS RDS Proxy 鎖定連線的方式,它與 Prisma Client 一起使用時不提供任何連線池優勢。
在 GitHub 上編輯此頁面