Ch2. 토폴로지와 환경 구성
Prisma + DB 프로덕션 토폴로지, 풀링, 다중 인스턴스 및 배포 구성
핵심 요약
- 온라인 트래픽은 PgBouncer/Proxy 풀링 계층으로, 마이그레이션은
DIRECT_DATABASE_URL직접 경로로 분리하고 읽기 부하는 리드 레플리카로 분산합니다. - 핫리로드 환경에서는 PrismaClient를
globalThis싱글턴으로 관리해 연결 폭증을 막습니다. - 총 연결 수 = (API 인스턴스 × 풀 상한) + 워커 + 운영 도구로 산정하고 DB 최대 연결의 70~80%를 넘기지 않습니다.
- Prisma ORM v7.4.0의 내장 LRU 쿼리 캐싱은 opt-out 자동 적용으로 SQL 재컴파일을 줄이며, Postgres
cacheStrategy와는 별개입니다. - 서버리스 워크로드는 콜드 스타트로 연결 비용이 급증하므로 풀링 계층을 두고 장시간 트랜잭션은 함수 밖으로 분리합니다.
Prisma 7.10.1 패키지·접속 경로 고정
다음은 PostgreSQL + Prisma 7용 설정입니다. 8 RC의 별도 runtime package·contract·마이그레이션 명령을 섞지 않습니다. 개발용 CLI도 프로젝트 의존성으로 설치하고 CI에서는 lockfile을 유지합니다.
pnpm add -D --save-exact prisma@7.10.1
pnpm add --save-exact @prisma/client@7.10.1 @prisma/adapter-pg@7.10.1
pnpm add pg dotenv
pnpm exec prisma --version// prisma/schema.prisma
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
}// prisma.config.ts — CLI만 사용하는 직접 연결
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: { path: 'prisma/migrations' },
datasource: { url: env('DIRECT_DATABASE_URL') },
})환경 변수 이름을 나눠 두는 것만으로 CLI가 직접 연결을 고르지는 않습니다. prisma.config.ts의 datasource.url을 실제로 연결해야 합니다. 런타임의 DATABASE_URL은 아래 adapter에 전달합니다.
근거: Prisma 7 전환, Accelerate 연결 전환.
권장 토폴로지
- 온라인 트래픽은 연결 풀 계층을 통해 접속
- 마이그레이션은
DIRECT_DATABASE_URL로 직접 접속 - 읽기 부하는 리드 레플리카로 분산(ORM 레벨 또는 리포팅 파이프라인)
Node 런타임에서 PrismaClient 수명 관리
// src/lib/prisma.ts — prisma generate 뒤 생성된 entrypoint 사용
import { PrismaClient } from '../generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'
const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient }
export function getPrisma() {
if (!globalForPrisma.prisma) {
const connectionString = process.env.DATABASE_URL
if (!connectionString) throw new Error('DATABASE_URL is required at runtime')
const adapter = new PrismaPg({
connectionString,
max: 10,
connectionTimeoutMillis: 5_000,
})
globalForPrisma.prisma = new PrismaClient({ adapter, log: ['warn', 'error'] })
}
return globalForPrisma.prisma
}Prisma 7의 새 prisma-client generator는 생성한 경로에서 import하고 PostgreSQL driver adapter를 전달합니다. max: 10·5초는 예시 운영 정책이며 서비스 한도가 아닙니다. 실제 DB 작업 시점에 생성하므로 빌드 중 import만으로 연결 정보를 요구하지 않습니다. 싱글턴은 프로세스마다 하나이며 여러 인스턴스의 연결 풀을 합치지는 않습니다.
연결 수 산정 기본식
총 연결 수 = (API 인스턴스 수 x 인스턴스당 Prisma 풀 상한) + 배치/워커 연결 + 운영 도구 연결DB 최대 연결의 70~80%를 초과하지 않도록 상한을 잡고, 나머지는 관리/장애 대응 여유로 남깁니다.
쿼리 캐싱 레이어 (v7.4.0+)
Prisma ORM v7.4.0부터 내장 LRU 쿼리 캐싱이 들어왔습니다. 같은 형태의 쿼리가 반복되면 SQL 재컴파일을 건너뛰어 이벤트 루프 경합을 줄입니다.
- 별도 설정 없이 자동 적용 (opt-out 방식)
- Prisma Postgres의
cacheStrategy(TTL/SWR)와는 별개 — ORM 레벨 컴파일 캐시 - v7.3.0의
compilerBuild: "fast" | "small"옵션과 함께 사용하면 컴파일러 성능 추가 조정 가능
서버리스/짧은 수명 워크로드 주의점
- 콜드 스타트가 많으면 연결 생성/해제 비용이 급증
- 풀링 계층 없이 직접 연결 시 DB 연결 한계에 빠르게 도달
- 장시간 트랜잭션 로직은 서버리스 함수에서 분리
Prisma 스키마/환경 변수 운영 팁
# 앱 런타임
DATABASE_URL="postgresql://app_prod:***@pgbouncer:6432/service"
# 마이그레이션/관리 작업
DIRECT_DATABASE_URL="postgresql://migrate_prod:***@primary:5432/service"prisma migrate deploy는 반드시 DIRECT_DATABASE_URL이 유효한 환경에서만 실행합니다.
배포 전 점검 항목
- 인스턴스 스케일 아웃 시 DB 연결 상한 재계산
- PgBouncer/Proxy 장애 시 우회 경로 문서화
- 리드 레플리카 지연 알림 임계치 설정
- 마이그레이션 전용 경로가 런타임 경로와 분리됨