고성능 소셜 API를 Bun & ElysiaJS로 $5 VPS에서 구축한 방법 (분당 3.6천 요청 처리)

발행: (2026년 1월 13일 오후 02:08 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

목표

마이크로‑소셜 API—Twitter와 같은 피드, 팔로우, 좋아요를 처리할 수 있는 백엔드 서비스를 비용을 크게 들이지 않고 만들고 싶었습니다.

  • 예산: 월 $5 – $20
  • 성능: 300 ms 이하 지연 시간
  • 규모: 동시 부하를 처리할 수 있어야 함 (스트레스 테스트)

대부분의 튜토리얼은 Hello World만 보여줍니다. 이 글에서는 저렴한 VPS에서 25명의 동시 사용자가 Hello World에 접근했을 때 무슨 일이 일어나는지(스포일러: 서버가 다운됩니다)를 보여주고, 이를 어떻게 해결했는지 설명합니다.

스택 🛠️

  • 런타임: Bun
  • 프레임워크: ElysiaJS (가장 빠른 Bun 프레임워크)
  • 데이터베이스: PostgreSQL (Dokploy 사용)
  • ORM: Drizzle (경량·타입‑안전)
  • 호스팅: Dokploy이 적용된 VPS (Docker Compose)

“오 이런” 순간 🚨

첫 번째 버전을 배포했을 때는 정상적으로 동작했습니다. 그 뒤 k6을 이용해 25명의 가상 사용자가 다양한 피드를 탐색하도록 부하 테스트를 실행했습니다.

k6 run tests/stress-test.js

결과

✗ http_req_failed................: 86.44%
✗ status is 429..................: 86.44%

서버가 다운된 것은 아니었지만, 거의 모든 요청을 거부하고 있었습니다.

진단

처음엔 Traefik(리버스 프록시) 때문이라고 생각했습니다. 코드를 파고들어 보니 범인은 나 자신이었습니다.

// src/index.ts
// OLD CONFIGURATION
.use(rateLimit({
  duration: 60_000,
  max: 100 // 💀 1분당 100 요청... IP당 전역?
}))

스트레스 테스트(그리고 대부분의 NAT된 사무실)에서는 모든 요청이 단일 IP에서 발생했기 때문에, 사실상 자신을 DDOS하고 있던 셈이었습니다.

해결 방법 🔧

1. Rate Limiter 튜닝

제한을 2,500 req/min으로 올렸습니다. 이는 남용을 방지하면서도 정상적인 대량 트래픽(또는 로드밸런서)을 허용합니다.

// src/index.ts
.use(rateLimit({
  duration: 60_000,
  max: 2500 // 표준적인 신뢰성 API에 훨씬 적합
}))

2. 데이터베이스 연결 풀링

PostgreSQL 기본 풀 크기는 보통 작습니다(예: 10~20). 내 VPS는 4 GB RAM을 가지고 있으며, PostgreSQL은 연결당 메모리를 필요로 하지만 그 정도는 필요하지 않습니다. 풀 크기를 80 연결로 늘렸습니다.

// src/db/index.ts
const client = postgres(process.env.DATABASE_URL, {
  max: 80
});

3. Docker를 이용한 수평 확장

Node/Bun은 단일 스레드입니다. 하나의 컨테이너는 하나의 CPU 코어만 효율적으로 사용합니다. 내 VPS는 2 vCPU를 가지고 있으므로 docker-compose.dokploy.ymlreplicas 지시자를 추가했습니다.

api:
  build: .
  restart: always
  deploy:
    replicas: 2 # 코어당 하나씩!

Traefik이 두 컨테이너 사이를 자동으로 로드밸런싱해 주어 처리량이 즉시 두 배가 됩니다.

최종 결과 🟢

다시 k6을 실행합니다:

k6 run tests/stress-test.js

성과

✓ checks_succeeded...: 100.00%
✓ http_req_duration..: p(95)=200.45ms
✓ http_req_failed....: 0.00% (excluding auth checks)

오류 0개, 저렴한 VPS에서도 약 200 ms 지연을 기록했습니다.

교훈

사이드 프로젝트에 Kubernetes가 필요하지 않습니다. 병목 현상이 어디에 있는지 이해하면 됩니다:

  • 애플리케이션 레이어: Rate limit을 확인하세요.
  • 데이터베이스 레이어: 연결 풀을 확인하세요.
  • 하드웨어: 모든 코어를 활용하세요(복제본).

API를 직접 사용해 보고 싶다면 Micro‑Social API가 RapidAPI에 공개되어 있습니다:

https://rapidapi.com/ismamed4/api/micro-social

행복한 코딩 되세요! 🚀

Back to Blog

관련 글

더 보기 »