跳到主要內容

資料庫連線

資料庫可以處理的併發連線數是有限的。每個連線都需要佔用 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 引數。
  • 您可以選擇性地調優連線池大小

如果您有**多個**應用程式例項

長期執行應用程式中的 PrismaClient

在**長期執行**的應用程式中,我們建議您

  • ✔ 建立 PrismaClient 的**一個**例項並在您的應用程式中重複使用
  • 僅在開發環境中PrismaClient 分配給全域性變數,以防止熱過載建立新例項

重複使用單個 PrismaClient 例項

要重複使用單個例項,請建立一個匯出 PrismaClient 物件的模組

client.ts
import { PrismaClient } from '@prisma/client'

let prisma = new PrismaClient()

export default prisma

該物件在模組首次匯入時被快取。後續請求將返回快取的物件,而不是建立新的 PrismaClient

app.ts
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 僅作為開發環境中的全域性變數儲存,因為全域性變數不會被重新載入

client.ts
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 的方式不會改變

app.ts
import { prisma } from './client'

async function main() {
const allUsers = await prisma.user.findMany()
}

main()

每個 CLI 命令建立的連線數

在對 Postgres、MySQL 和 SQLite 進行的本地測試中,每個 Prisma CLI 命令通常使用單個連線。下表顯示了這些測試中觀察到的範圍。您的環境可能會產生略微不同的結果。

命令連線數描述
migrate status1檢查遷移狀態
migrate dev1–4在開發環境中應用待處理的遷移
migrate diff1–2將資料庫 schema 與遷移歷史進行比較
migrate reset1–2重置資料庫並重新應用遷移
migrate deploy1–2在生產環境中應用待處理的遷移
db pull1將資料庫 schema 拉取到 Prisma schema 中
db push1–2將 Prisma schema 推送到資料庫
db execute1執行原始 SQL 命令
db seed1使用初始資料填充資料庫

無伺服器環境 (FaaS)

無伺服器環境的示例包括託管在 AWS Lambda、Vercel 或 Netlify Functions 上的 Node.js 函式。請使用以下清單作為無伺服器環境中連線管理的指南

無伺服器挑戰

在無伺服器環境中,每個函式都會建立 PrismaClient 的**自己的例項**,並且每個客戶端例項都有自己的連線池。

考慮以下示例,其中單個 AWS Lambda 函式使用 PrismaClient 連線到資料庫。connection_limit3

An AWS Lambda function connecting to a database.

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

Three AWS Lambda function connecting to a database.

200 個併發函式(因此可能有 600 個連線)響應流量高峰 📈 可以非常迅速地耗盡資料庫連線限制。此外,任何處於**暫停**狀態的函式預設會保持其連線開啟,並阻止它們被其他函式使用。

  1. 首先connection_limit 設定為 1
  2. 如果較小的連線池大小不足,請考慮使用外部連線池器,例如 PgBouncer

無伺服器環境中建議的連線池大小 (connection_limit) 取決於

沒有外部連線池器

如果您**沒有**使用外部連線池器,首先將連線池大小 (connection_limit) 設定為 1,然後進行最佳化。每個傳入請求都會啟動一個短生命週期的 Node.js 程序,在流量高峰期間,許多具有高 connection_limit 的併發函式會迅速**耗盡資料庫連線限制**。

以下示例演示瞭如何在連線 URL 中將 connection_limit 設定為 1

postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public&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_limitpool_timeout 引數。

增加連線池大小

注意

截至 v6.7.0,Prisma ORM 具有 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 上編輯此頁面

© . This site is unofficial and not affiliated with Prisma Data, Inc.