Vercel ProPlan 대량 트래픽 처리
Vercel Pro 플랜에서 대량의 트래픽을 효과적으로 처리하는 방법을 알아봅니다.
Vercel ProPlan 대량 트래픽 처리
Introduction
대량의 트래픽을 처리하는 것은 온라인 비즈니스에 중요합니다. Vercel Pro 플랜에서 대량 트래픽을 효과적으로 처리하는 방법을 알아보겠습니다.
Environment
- Vercel Pro 플랜
- Next.js 14+
- 글로벌 CDN
- 서버리스 함수
Problem
대량 트래픽 시 발생하는 문제:
Error: FUNCTION_INVOCATION_TIMEOUT
Error: TOO_MANY_REQUESTS
Error: RATE_LIMIT_EXCEEDEDAnalysis
Vercel Pro 플랜의 특징:
- 서버리스 함수 확장: 자동 확장 지원
- 글로벌 CDN: 전 세계 빠른 전달
- DDoS 보호: 기본적인 DDoS 보호
- 분석 도구: 트래픽 분석 제공
Solution
1. 캐싱 전략 수립
// lib/cache-strategy.js
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
export async function getCachedResponse(key, fetchFn, ttl = 300) {
// 캐시 확인
const cached = await redis.get(key);
if (cached) {
return JSON.parse(cached);
}
// 데이터 가져오기
const data = await fetchFn();
// 캐시 저장
await redis.setex(key, ttl, JSON.stringify(data));
return data;
}
// 사용 예시
export async function getPopularProducts() {
return getCachedResponse(
'popular-products',
() => prisma.product.findMany({
where: { popularity: { gt: 100 } },
take: 20,
}),
600 // 10분 캐시
);
}2. 레이트 리밋링 구현
// lib/rate-limiter.js
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
export async function checkRateLimit(identifier, limit = 100, window = 60) {
const key = `ratelimit:${identifier}`;
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, window);
}
return {
allowed: current <= limit,
remaining: Math.max(0, limit - current),
reset: Date.now() + (window * 1000),
};
}
// 미들웨어에서 사용
export async function rateLimitMiddleware(request) {
const ip = request.headers.get('x-forwarded-for') || 'unknown';
const rateLimit = await checkRateLimit(ip, 100, 60);
if (!rateLimit.allowed) {
return new Response('Too Many Requests', {
status: 429,
headers: {
'X-RateLimit-Remaining': '0',
'X-RateLimit-Reset': rateLimit.reset.toString(),
},
});
}
return null;
}3. CDN 최적화
// next.config.js
module.exports = {
headers: async () => [
{
source: '/api/:path*',
headers: [
{ key: 'Cache-Control', value: 's-maxage=60, stale-while-revalidate=300' },
],
},
{
source: '/static/:path*',
headers: [
{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' },
],
},
],
};4. 서버리스 함수 최적화
// app/api/optimized/route.js
export const runtime = 'edge';
export const maxDuration = 30;
export async function GET(request) {
const response = await fetch('https://api.external.com/data', {
next: { revalidate: 60 },
});
return Response.json(await response.json());
}5. 모니터링 및 알림
// lib/monitoring.js
export async function trackTrafficMetrics() {
const metrics = {
timestamp: Date.now(),
requests: await getRequestCount(),
errors: await getErrorCount(),
latency: await getAverageLatency(),
};
// 메트릭 저장
await saveMetrics(metrics);
// 임계값 초과 시 알림
if (metrics.requests > 1000) {
await sendAlert('High traffic detected');
}
return metrics;
}6. 오토 스케일링 설정
// vercel.json
{
"functions": {
"app/api/**/*.js": {
"memory": 512,
"maxDuration": 30
}
},
"regions": ["iad1", "sfo1", "cdg1", "hnd1"]
}7. 비용 최적화
// lib/cost-optimizer.js
export function analyzeCosts(usage) {
const costs = {
bandwidth: usage.bandwidth * 0.15 / 1000, // $0.15/GB
functions: usage.functionExecutions * 0.000018,
build: usage.buildMinutes * 0.01,
storage: usage.storage * 0.023 / 1000, // $0.023/GB
};
const total = Object.values(costs).reduce((a, b) => a + b, 0);
return {
breakdown: costs,
total,
recommendations: getCostRecommendations(usage),
};
}Lessons Learned
- 캐싱 전략: 자주 접근되는 데이터는 캐싱하여 서버 부하를 줄여야 합니다.
- 레이트 리밋링: API 남용을 방지하기 위한 레이트 리밋링이 필요합니다.
- CDN 활용: 정적 리소스는 CDN을 통해 전달하면 성능이 향상됩니다.
- 모니터링: 트래픽 패턴을 모니터링하여 대응해야 합니다.
- 비용 관리: 사용량을 모니터링하여 비용을 최적화해야 합니다.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.