콘텐츠로 이동

실전 토폴로지 (AI 추론 서비스 예시)

다음은 AI 추론 서비스의 프로덕션 수준 전체 구조입니다.

┌─────────────────────────────────────────────────────────┐
│ 사용자 │
└───────────────────────────┬─────────────────────────────┘
│ HTTPS
┌─────────────────────────────────────────────────────────┐
│ DNS (Route 53) │
│ example.com → ALB 도메인 CNAME │
└───────────────────────────┬─────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ CDN (CloudFront / Cloudflare) │
│ 정적 에셋 캐싱 (JS/CSS/이미지), Edge에서 서빙 │
│ 동적 /api/* 요청은 오리진(ALB)으로 통과 │
└────────────────┬──────────────────────────┬─────────────┘
│ 정적 캐시 히트 │ 캐시 미스 / API
▼ ▼
[Edge 서버 응답] ┌──────────────────────────────┐
│ ALB (Application LB, L7) │
│ SSL 종료, 헬스체크 │
└───────┬──────────────────────┘
┌────────────────┼────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐
│ nginx + FastAPI │ │nginx+FastAPI│ │ nginx + FastAPI │
│ 워커 인스턴스1 │ │ 워커2 │ │ 워커3 │
│ (CPU, t3.large) │ │ (CPU) │ │ (CPU) │
└────────┬────────┘ └──────┬──────┘ └────────┬────────┘
│ │ │
└────────┬────────┘──────────────────┘
│ 짧은 추론 (동기 처리)
│ 긴 추론 (큐로 전달)
┌─────────────────────────────────────────────┐
│ 메시지 큐 (Redis / SQS) │
│ 장시간 추론 작업 대기열 │
└──────────────┬──────────────────────────────┘
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ GPU 워커 1 │ │ GPU 워커 2 │ │ GPU 워커 N │
│ g5.xlarge │ │ g5.xlarge │ │ (오토스케일) │
│ A10G GPU │ │ A10G GPU │ │ │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
└────────────────┼─────────────────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ PostgreSQL │ │ Redis │ │ VectorDB │
│ RDS Multi-AZ │ │ ElastiCache │ │ (Pinecone / │
│ 사용자·로그 │ │ 세션·캐시 │ │ pgvector) │
└──────────────┘ └──────────────┘ └──────────────┘

DNS(Route 53)는 도메인을 ALB의 DNS 이름으로 연결합니다. ALB IP는 동적으로 바뀔 수 있으므로 IP가 아닌 ALB DNS 이름으로 CNAME을 설정합니다.

CDN(CloudFront)은 전 세계 엣지 서버에 정적 에셋을 캐싱합니다. 서울 사용자는 서울 엣지에서 JS/CSS를 받습니다. 미국 원본 서버까지 왕복하지 않아도 됩니다. /api/* 요청은 CDN이 캐싱하지 않고 ALB로 통과시킵니다.

ALB는 L7 로드밸런서입니다. SSL 인증서를 여기서 관리합니다. 백엔드 FastAPI 워커들의 헬스체크를 수행해 비정상 인스턴스로는 요청을 보내지 않습니다.

ALB 라우팅 규칙 예시:
Host: example.com, Path: /api/* → FastAPI 타겟 그룹
Host: example.com, Path: /* → 정적 파일 타겟 그룹 (또는 S3)

입력 검증, 인증, 간단한 비즈니스 로직을 처리합니다. 짧은 추론(수초 이내)은 직접 GPU 워커 API를 호출하고 응답을 기다립니다. 긴 추론(수십 초 이상)은 작업을 큐에 넣고 즉시 job_id를 반환합니다.

@app.post("/api/inference")
async def run_inference(request: InferenceRequest, background_tasks: BackgroundTasks):
if request.estimated_seconds < 10:
# 짧은 추론: 동기 처리
result = await gpu_worker_client.infer(request)
return {"result": result}
else:
# 긴 추론: 큐 전달
job_id = await queue.enqueue(request.model_dump())
return {"job_id": job_id, "status": "queued"}
@app.get("/api/jobs/{job_id}")
async def get_job_status(job_id: str):
status = await redis_client.get(f"job:{job_id}:status")
result = await redis_client.get(f"job:{job_id}:result")
return {"status": status, "result": result}

GPU 인스턴스는 비쌉니다. 항상 최대 수를 켜두면 비용이 폭증합니다. 큐의 대기 메시지 수를 지표로 오토스케일링합니다.

[GPU 오토스케일링 전략]
지표: Redis 큐 대기 메시지 수
> 10개 → GPU 워커 +1 (스케일 아웃)
< 2개 → GPU 워커 -1 (스케일 인, 최소 1대 유지)
GPU 인스턴스 시작 시간: ~3분 (AMI에 모델 미리 로드)
→ 시작 후 큐에서 작업 폴링 시작
스팟 인스턴스 활용:
- On-Demand 1대 (최소 보장)
- Spot 나머지 (비용 70% 절감, 중단 가능성 처리 필요)

모델 가중치 로딩 시간을 줄이려면 GPU 인스턴스용 커스텀 AMI에 모델을 미리 포함시킵니다. 인스턴스 시작 시 모델 다운로드가 필요 없어 준비 시간이 수분에서 수십 초로 줄어듭니다.

PostgreSQL (RDS Multi-AZ):
- 사용자 계정, 구독, API 키
- 추론 요청 이력 및 비용 추적
- Multi-AZ로 장애 시 자동 페일오버
Redis (ElastiCache):
- 세션 토큰
- 중복 요청 캐시 (동일 입력 → 캐시된 결과 반환)
- 작업 큐 (List 자료구조)
- 결과 임시 저장 (job_id → result, TTL 1시간)
VectorDB (pgvector 또는 Pinecone):
- 문서 임베딩 저장 (RAG 시스템)
- 코사인 유사도 기반 검색
- pgvector: PostgreSQL 확장, 기존 RDS에서 운영 가능
- Pinecone: 관리형 서비스, 대규모에서 운영 부담 없음

HTTP 요청은 일반적으로 30~60초 타임아웃이 있습니다. LLM 응답 생성, 이미지 생성, 영상 처리처럼 수분이 걸리는 작업은 동기 HTTP로 처리할 수 없습니다.

[큐 패턴 흐름]
클라이언트 → POST /api/jobs → {job_id: "abc123"} (즉시 반환)
클라이언트 → GET /api/jobs/abc123 → {status: "processing"} (폴링)
클라이언트 → GET /api/jobs/abc123 → {status: "done", result: ...}
또는 WebSocket / SSE로 완료 알림:
클라이언트 ← SSE stream ← 작업 완료 이벤트

폴링보다 SSE(Server-Sent Events)나 WebSocket이 실시간성이 좋지만, 구현 복잡도가 높습니다. 실제 서비스에서는 추론 시간이 5초 이내면 동기, 그 이상이면 큐 패턴을 사용하는 혼합 전략이 현실적입니다.

  • AI 추론 서비스의 요청 흐름은 DNS → CDN → ALB → nginx/FastAPI 워커 → GPU 워커 → DB/Redis/VectorDB 순이다.
  • CDN은 정적 에셋을 엣지에서 서빙하고, ALB는 FastAPI 워커들에 L7 로드밸런싱과 SSL 종료를 담당한다.
  • GPU 워커는 큐(Redis/SQS) 대기 메시지 수를 기반으로 오토스케일링한다. 스팟 인스턴스로 비용을 70% 절감할 수 있다.
  • 장시간 추론(수분)은 동기 HTTP로 처리할 수 없다. 큐에 작업을 넣고 job_id를 반환한 뒤 클라이언트가 폴링하거나 SSE로 완료를 수신한다.
  • 데이터 계층은 역할별로 분리된다. 구조화 데이터는 PostgreSQL, 세션·캐시·큐는 Redis, 임베딩 검색은 VectorDB가 담당한다.