Skip to main content

클라이언트-서버 구조

클라이언트는 요청을 만들고, 서버는 검증/처리/저장을 수행한 뒤 응답을 반환합니다. 이 구조를 이해하면 장애를 계층별로 분리해 해결할 수 있습니다.

학습 목표

  • 요청이 서버 내부를 어떻게 통과하는지 설명할 수 있습니다.
  • 상태 관리(stateless/stateful) 선택 기준을 알 수 있습니다.
  • 동기/비동기 통신의 차이와 적용 기준을 이해합니다.
  • AI 서빙 아키텍처의 기본 패턴을 설계할 수 있습니다.

왜 중요한가

AI/ML 모델은 결국 서비스로 배포되어야 가치를 만듭니다. 클라이언트-서버 구조를 이해하지 못하면, 모델은 만들었지만 사용자에게 전달할 수 없는 상황이 됩니다. 추론 지연, 동시 요청 처리, 장애 대응 모두 이 구조 위에서 설계됩니다.

요청 처리 생명주기

Client ──→ Load Balancer ──→ API Server ──→ Business Logic ──→ DB/Cache/외부 API
  │              │                │                │                    │
  │              │                │                │                    │
  └──────────────└────────────────└────────────────└────────────────────┘
                              ← Response (상태코드 + 바디)
  1. 클라이언트가 요청(헤더, 바디, 인증 정보)을 전송합니다.
  2. 서버가 인증/인가와 입력 검증을 수행합니다.
  3. 비즈니스 로직이 DB/캐시/외부 API를 호출합니다.
  4. 결과를 직렬화해 상태코드와 함께 응답합니다.
  5. 로그, 메트릭, 트레이스를 남깁니다.

상태 관리 핵심

구분statelessstateful
요청 독립성각 요청이 독립적이전 요청 상태에 의존
확장성수평 확장 용이세션 고정 필요
장애 복구다른 서버로 즉시 전환세션 유실 위험
적합한 상황REST API, 추론 서비스채팅(대화 상태), 게임
초기 API는 가능하면 stateless로 시작하고, 필요한 상태는 DB/캐시에 명시적으로 저장하세요.

동기 vs 비동기 통신

구분동기(Synchronous)비동기(Asynchronous)
응답 방식요청 → 대기 → 즉시 응답요청 → job_id 반환 → 나중에 결과 조회
적합한 작업짧은 추론(< 10초)파인튜닝, 배치 처리, 이미지 생성
타임아웃 위험높음 (긴 작업 시)낮음
구현 복잡도낮음중간 (큐 + 워커 필요)
# 비동기 패턴 예시: 작업 제출 → 상태 조회
# POST /jobs → {"job_id": "abc-123", "status": "pending"}
# GET /jobs/abc-123 → {"status": "completed", "result": {...}}
비동기 작업은 큐 기반(Redis Queue, SQS, Pub/Sub)으로 분리하고, 클라이언트에는 job_id와 상태 조회 API를 제공합니다.

AI 서빙 아키텍처 패턴

패턴 1: 단일 API 서버 (소규모)

Client → FastAPI + 모델 (단일 서버)
  • 장점: 단순, 빠른 시작
  • 단점: 확장 어려움, 모델 업데이트 시 다운타임

패턴 2: API + 추론 분리 (중규모)

Client → API Server → Message Queue → Inference Worker (GPU)
                  ↗                            ↓
         결과 조회 API  ←──── Result Store (Redis/DB)
  • 장점: GPU 워커 독립 스케일링, API 안정성
  • 단점: 구현 복잡도 증가

패턴 3: 마이크로서비스 (대규모)

Client → API Gateway → Auth Service
                    → Prompt Service
                    → Inference Service (GPU)
                    → Logging Service
  • 장점: 독립 배포/스케일링, 장애 격리
  • 단점: 운영 복잡도 높음, 네트워크 지연 증가
초기에는 패턴 1로 시작하고, 트래픽과 복잡도가 증가하면 패턴 2로 전환하세요. 마이크로서비스는 팀 규모와 운영 역량이 충분할 때 고려합니다.
  1. 모델 추론 시간이 길어 API 타임아웃 발생
  2. 외부 LLM API 지연으로 전체 요청이 지연
  3. DB 연결 풀 부족으로 대기열 증가 병목은 보통 한 계층이 아니라 여러 계층에서 동시에 발생합니다.
요청-응답 경로에서 무거운 작업까지 같이 수행하면 장애 전파가 빨라집니다. 무거운 작업은 큐/워커로 분리하고, API는 결과 조회를 담당하게 분리하세요.
상태코드 분포(4xx/5xx), p95 지연시간, 외부 API 실패율, DB 지연을 순서대로 확인하세요. 코드 디버깅 전에 계층별 지표를 먼저 보면 원인 범위를 빠르게 줄일 수 있습니다.
LLM 응답처럼 토큰 단위로 생성되는 경우, Server-Sent Events(SSE)로 스트리밍하면 사용자 체감 대기 시간을 크게 줄일 수 있습니다. text/event-stream Content-Type으로 응답하고, 클라이언트는 EventSource로 수신합니다.

체크리스트

  • 요청 타임아웃/재시도 정책이 문서화되어 있나요?
  • 장기 작업이 API 경로에서 분리되어 있나요?
  • 요청 ID로 로그 추적이 가능한가요?
  • 동기/비동기 처리 기준이 정의되어 있나요?
  • 스케일링 전략(수평/수직)이 계획되어 있나요?

다음 문서