Skip to content

필사 모드: 토스뱅크 ML Backend Engineer 합격을 위한 완벽 가이드: 서버 아키텍처·ML 서빙·공부 로드맵

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

1. 토스뱅크 ML Service Team 분석

1-1. 팀의 미션과 역할

토스뱅크 ML Service Team은 은행 서비스 전반에 걸쳐 AI/ML 기술을 프로덕션 레벨로 서빙하는 핵심 팀입니다. 단순히 모델을 만드는 것이 아니라, 수천만 사용자가 실시간으로 이용하는 금융 서비스에 ML 모델을 안정적으로 배포하고 운영하는 것이 이 팀의 존재 이유입니다.

금융 도메인의 특수성을 고려하면, ML Service Team이 다루는 기술적 난이도는 일반 IT 기업보다 한 단계 높습니다.

- **가용성 요구사항**: 은행 서비스는 24/7 무중단 운영이 필수이며, 서비스 중단은 곧 금전적 손실과 규제 이슈로 직결됩니다

- **응답 속도 제약**: 신용평가, 이상거래 탐지 등은 밀리초 단위의 응답 속도가 요구됩니다

- **규제 준수**: 금융 데이터 처리에 관한 엄격한 규제를 기술적으로 충족해야 합니다

- **대규모 트래픽**: 토스 생태계의 수천만 사용자 트래픽을 안정적으로 처리해야 합니다

1-2. Data Scientist + ML Engineer 협업 구조

ML Service Team의 가장 큰 특징은 Data Scientist와 ML Engineer가 명확하게 역할을 분리하면서도 긴밀하게 협업하는 구조라는 점입니다.

**Data Scientist의 역할:**

- 비즈니스 문제를 ML 문제로 정의

- 모델 실험 및 학습 (실험 환경)

- 모델 성능 지표 정의 및 평가

- A/B 테스트 설계 및 결과 분석

**ML Backend Engineer의 역할:**

- 학습된 모델을 프로덕션에 서빙하는 인프라 구축

- 모델 서빙 API 설계 및 개발

- 서빙 성능 최적화 (지연시간, 처리량)

- 모델 버전 관리 및 배포 파이프라인 구축

- 모니터링 및 장애 대응

이 구조의 핵심은 **"Data Scientist가 모델에 집중하고, ML Backend Engineer가 서빙에 집중"**하는 분업 체계입니다. 서로의 전문 영역을 존중하면서 협업하기 때문에, ML Backend Engineer는 반드시 ML 전문가가 아니어도 됩니다. 대신 서버 아키텍처와 인프라에 대한 깊은 이해가 필수입니다.

1-3. 은행 업무 AI 제품

토스뱅크에서 ML이 적용되는 대표적인 영역을 살펴보겠습니다.

**신용평가 모델 서빙:**

- 대출 신청 시 실시간으로 신용점수를 산출해야 합니다

- P99 지연시간 100ms 이하가 일반적인 요구사항입니다

- 모델 업데이트 시 무중단 배포가 필수입니다

**이상거래 탐지 (FDS):**

- 모든 금융 거래를 실시간으로 분석합니다

- 초당 수만 건의 거래를 처리하는 처리량이 필요합니다

- False Positive를 최소화하면서 실제 사기를 놓치지 않아야 합니다

**개인화 추천:**

- 금융 상품 추천, 소비 패턴 분석 등

- 사용자별 실시간 피처를 기반으로 추론합니다

- Feature Store를 통한 피처 관리가 핵심입니다

**AI 챗봇:**

- 고객 문의에 자동으로 응답하는 시스템

- LLM 기반 서빙은 GPU 리소스 관리가 중요합니다

- RAG(Retrieval-Augmented Generation) 아키텍처 적용

1-4. 크로스펑셔널 협업

ML Backend Engineer는 기술만 잘한다고 되는 포지션이 아닙니다. 토스뱅크는 PO(Product Owner), 디자이너, 프론트엔드/백엔드 개발자, Data Scientist가 하나의 스쿼드를 구성하여 제품을 만드는 구조입니다.

- **PO와의 소통**: 비즈니스 요구사항을 기술적 제약 조건과 함께 논의

- **Data Scientist와의 소통**: 모델 서빙 요구사항 (지연시간, 배치 크기, 모델 포맷) 조율

- **프론트엔드 개발자와의 소통**: API 스펙 정의, 응답 포맷 협의

- **DevOps/SRE와의 소통**: 인프라 요구사항, 배포 전략, 모니터링 기준 설정

따라서 면접에서도 기술적 깊이뿐만 아니라 커뮤니케이션 역량을 평가할 가능성이 높습니다.

2. JD 완전 해부: 라인 바이 라인

이 섹션에서는 토스뱅크 ML Backend Engineer JD의 핵심 키워드를 하나씩 뜯어보며, 각 항목이 실제로 어떤 기술과 역량을 요구하는지 분석합니다.

2-1. "서버 아키텍처를 설계하고 개발"

이 문구는 단순한 CRUD API 개발이 아닙니다. **시스템 수준의 아키텍처 설계 능력**을 요구합니다.

**구체적으로 의미하는 것:**

- 서비스 간 통신 방식 선택 (동기 vs 비동기, REST vs gRPC)

- 데이터 흐름 설계 (어떤 데이터가 어디서 생성되어 어디로 흐르는가)

- 장애 격리 설계 (하나의 서비스 장애가 전체 시스템에 영향을 주지 않도록)

- 확장성을 고려한 설계 (수평 확장이 가능한 구조)

**핵심 패턴:**

- **CQRS (Command Query Responsibility Segregation)**: 읽기와 쓰기를 분리하여 각각 최적화

- **Event Sourcing**: 상태 변경을 이벤트로 기록하여 추적 가능성 확보

- **Saga Pattern**: 분산 트랜잭션을 관리하는 패턴

- **Strangler Fig Pattern**: 레거시 시스템을 점진적으로 마이그레이션하는 패턴

2-2. "대규모 트래픽을 안정적으로"

토스 생태계의 MAU(월간 활성 사용자)를 고려하면, "대규모"는 수천만 단위의 사용자 트래픽을 의미합니다.

**기술적 요구사항:**

- 초당 수만~수십만 건의 요청 처리 능력

- 피크 시간대(급여일, 이벤트 등) 급격한 트래픽 증가 대응

- 99.99% 이상의 서비스 가용성 유지

- 장애 발생 시 빠른 복구 (MTTR 최소화)

**필요한 기술:**

- 로드 밸런싱 전략 (L4/L7)

- 오토스케일링 (HPA, VPA, KEDA)

- 서킷 브레이커를 통한 장애 전파 방지

- 속도 제한(Rate Limiting)으로 시스템 보호

- 커넥션 풀링으로 리소스 효율화

- 비동기 처리로 처리량 극대화

2-3. "무거운 AI 모델을 안정적인 응답 속도로 서빙"

이 부분이 ML Backend Engineer의 핵심 차별점입니다. 일반 백엔드 엔지니어와 다른 점은 바로 **ML 모델 서빙에 대한 전문성**입니다.

**"무거운 AI 모델"이 의미하는 것:**

- 대형 딥러닝 모델 (수백 MB ~ 수 GB 크기)

- GPU 추론이 필요한 모델

- LLM 기반 모델 (수십억 파라미터)

- 앙상블 모델 (여러 모델의 조합)

**"안정적인 응답 속도"를 위한 기술:**

- 모델 최적화: ONNX 변환, TensorRT 가속, 양자화(Quantization)

- 배치 추론: 여러 요청을 묶어서 한 번에 처리

- 모델 캐싱: 자주 사용되는 추론 결과를 캐싱

- GPU 리소스 관리: GPU 메모리 최적화, Multi-Instance GPU(MIG) 활용

- 모델 서빙 프레임워크: Triton Inference Server, BentoML 등

2-4. "MSA 환경에서 분산 추적"

MSA 환경에서는 하나의 사용자 요청이 10개 이상의 마이크로서비스를 거칠 수 있습니다. 이때 문제가 발생하면 어디서 병목이 생겼는지, 어떤 서비스에서 에러가 발생했는지 추적하는 것이 **Observability**입니다.

**3가지 핵심 요소 (Three Pillars of Observability):**

1. **Traces (추적)**: 요청의 전체 경로를 시각화

- OpenTelemetry를 통한 계측(Instrumentation)

- Jaeger, Tempo 등으로 시각화

- Span, Trace ID, Parent-Child 관계 이해

2. **Metrics (메트릭)**: 시스템 상태를 숫자로 표현

- Prometheus를 통한 메트릭 수집

- RED 메트릭: Rate, Errors, Duration

- USE 메트릭: Utilization, Saturation, Errors

- Grafana로 대시보드 구성

3. **Logs (로그)**: 이벤트 기록

- 구조화된 로깅 (JSON 포맷)

- 로그 집계: ELK Stack, Loki

- 로그와 트레이스의 상관관계(Correlation)

2-5. "ML 경험 없어도 OK"

이 문구는 매우 중요한 시그널입니다. 토스뱅크가 이 포지션에서 진정으로 원하는 것은 **견고한 서버 개발 능력**이라는 뜻입니다.

**이것이 의미하는 바:**

- ML/DL 이론(CNN, RNN, Transformer 등)을 깊이 알 필요는 없습니다

- 대신 모델을 서빙하는 인프라, 서버, DevOps에 대한 전문성이 핵심입니다

- ML 도메인 지식은 입사 후 팀에서 학습할 수 있습니다

- 하지만 ML 서빙 프레임워크(Triton 등) 사용 경험이 있으면 큰 플러스입니다

**성장 기회:**

- ML 도메인 지식을 팀에서 자연스럽게 습득

- 최신 ML 인프라 기술을 실무에서 경험

- Data Scientist와 협업하며 ML 파이프라인 전체를 이해

- 금융 도메인 전문성도 함께 성장

3. 필수 기술스택 딥다이브

3-1. 서버 개발 (Python/Kotlin/Go)

토스뱅크 JD에서 언급된 세 가지 언어를 각각 깊이 분석합니다. 모든 언어를 다 알 필요는 없지만, 최소 하나는 깊이 있게, 나머지 하나는 기본적으로 다룰 수 있어야 합니다.

Python: ML 서빙의 핵심 언어

Python은 ML 생태계의 중심 언어이므로, ML Backend Engineer에게 가장 중요한 언어입니다.

**FastAPI (비동기 웹 프레임워크):**

from fastapi import FastAPI, HTTPException

from pydantic import BaseModel

app = FastAPI()

class PredictionRequest(BaseModel):

user_id: str

features: list[float]

class PredictionResponse(BaseModel):

score: float

model_version: str

latency_ms: float

@app.post("/predict", response_model=PredictionResponse)

async def predict(request: PredictionRequest):

start = asyncio.get_event_loop().time()

모델 추론 로직

score = await run_inference(request.features)

elapsed = (asyncio.get_event_loop().time() - start) * 1000

return PredictionResponse(

score=score,

model_version="v2.1.0",

latency_ms=round(elapsed, 2)

)

**asyncio 기반 비동기 프로그래밍:**

async def fetch_features(user_id: str) -> dict:

"""Feature Store에서 사용자 피처를 비동기로 조회"""

async with aiohttp.ClientSession() as session:

async with session.get(

f"http://feature-store/v1/features/user_id/{user_id}"

) as response:

return await response.json()

async def parallel_feature_fetch(user_ids: list[str]) -> list[dict]:

"""여러 사용자의 피처를 병렬로 조회"""

tasks = [fetch_features(uid) for uid in user_ids]

return await asyncio.gather(*tasks)

**Pydantic을 활용한 데이터 검증:**

from pydantic import BaseModel, Field, validator

class ModelConfig(BaseModel):

model_name: str = Field(..., description="모델 이름")

model_version: str = Field(..., regex=r"^v\d+\.\d+\.\d+$")

batch_size: int = Field(default=32, ge=1, le=512)

timeout_ms: int = Field(default=100, ge=10, le=5000)

@validator("model_name")

def validate_model_name(cls, v):

allowed = ["credit_score", "fds", "recommender", "chatbot"]

if v not in allowed:

raise ValueError(f"허용되지 않는 모델: {v}")

return v

**추천 학습 자료 (Python):**

- FastAPI 공식 문서 (fastapi.tiangolo.com)

- "Architecture Patterns with Python" - Harry Percival, Bob Gregory

- Real Python: asyncio 튜토리얼

- uvicorn + gunicorn 배포 가이드

Kotlin: 엔터프라이즈 서버 개발

Kotlin은 토스 생태계에서 핵심 언어 중 하나이며, Spring Boot 기반의 서비스 개발에 사용됩니다.

**Spring Boot + Coroutines:**

@RestController

@RequestMapping("/api/v1/models")

class ModelServingController(

private val inferenceService: InferenceService,

private val featureStore: FeatureStore

) {

@PostMapping("/predict")

suspend fun predict(

@RequestBody request: PredictionRequest

): PredictionResponse {

val startTime = System.nanoTime()

// 비동기로 피처 조회

val features = featureStore.getFeatures(request.userId)

// 모델 추론

val result = inferenceService.infer(

modelName = request.modelName,

features = features

)

val latencyMs = (System.nanoTime() - startTime) / 1_000_000.0

return PredictionResponse(

score = result.score,

modelVersion = result.version,

latencyMs = latencyMs

)

}

}

**Coroutines를 활용한 병렬 처리:**

suspend fun fetchMultipleFeatures(

userIds: List<String>

): List<FeatureSet> = coroutineScope {

userIds.map { userId ->

async(Dispatchers.IO) {

featureStore.getFeatures(userId)

}

}.awaitAll()

}

**추천 학습 자료 (Kotlin):**

- Kotlin 공식 문서 (kotlinlang.org)

- "Kotlin in Action" - Dmitry Jemerov

- Spring Boot + Kotlin 공식 가이드

- Kotlin Coroutines 공식 가이드

Go: 고성능 시스템 프로그래밍

Go는 인프라 도구, API 게이트웨이, 사이드카 프록시 등 성능이 중요한 컴포넌트에 사용됩니다.

**Gin 기반 API 서버:**

package main

"context"

"net/http"

"time"

"github.com/gin-gonic/gin"

)

type PredictionRequest struct {

UserID string `json:"user_id" binding:"required"`

Features []float64 `json:"features" binding:"required"`

}

type PredictionResponse struct {

Score float64 `json:"score"`

ModelVersion string `json:"model_version"`

LatencyMs float64 `json:"latency_ms"`

}

func predictHandler(c *gin.Context) {

var req PredictionRequest

if err := c.ShouldBindJSON(&req); err != nil {

c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})

return

}

start := time.Now()

ctx, cancel := context.WithTimeout(

c.Request.Context(),

100*time.Millisecond,

)

defer cancel()

score, err := runInference(ctx, req.Features)

if err != nil {

c.JSON(http.StatusInternalServerError,

gin.H{"error": "inference failed"})

return

}

latency := float64(time.Since(start).Microseconds()) / 1000.0

c.JSON(http.StatusOK, PredictionResponse{

Score: score,

ModelVersion: "v2.1.0",

LatencyMs: latency,

})

}

**goroutine과 channel을 활용한 동시성:**

func batchInference(

ctx context.Context,

requests []InferenceRequest,

) ([]InferenceResult, error) {

results := make([]InferenceResult, len(requests))

errChan := make(chan error, len(requests))

for i, req := range requests {

go func(idx int, r InferenceRequest) {

result, err := runSingleInference(ctx, r)

if err != nil {

errChan <- err

return

}

results[idx] = result

errChan <- nil

}(i, req)

}

for range requests {

if err := <-errChan; err != nil {

return nil, err

}

}

return results, nil

}

**추천 학습 자료 (Go):**

- Go 공식 투어 (tour.golang.org)

- "Go Programming Language" - Donovan, Kernighan

- "Concurrency in Go" - Katherine Cox-Buday

- Go by Example (gobyexample.com)

언어 선택 가이드

| 기준 | Python | Kotlin | Go |

| ----------- | ------------ | ---------------- | ---------------- |

| ML 생태계 | 최고 | 보통 | 제한적 |

| 서버 성능 | 보통 | 좋음 | 최고 |

| 동시성 모델 | asyncio | Coroutines | goroutine |

| 학습 곡선 | 낮음 | 중간 | 낮음 |

| 토스 생태계 | ML 서빙 | 비즈니스 로직 | 인프라 도구 |

| 추천 대상 | ML 서빙 중심 | 서비스 개발 중심 | 인프라/도구 중심 |

**권장 조합:**

- **메인 언어 1개** + **서브 언어 1개** 전략

- ML 서빙 중심이라면: Python(메인) + Kotlin 또는 Go(서브)

- 서비스 개발 중심이라면: Kotlin(메인) + Python(서브)

3-2. 견고한 서버 아키텍처

Design Patterns

**CQRS (Command Query Responsibility Segregation):**

읽기와 쓰기를 분리하는 패턴입니다. ML 서빙에서는 모델 업데이트(Command)와 추론 요청(Query)을 분리할 수 있습니다.

[모델 업데이트 요청] --> Command Service --> Model Registry --> Event Bus

[추론 요청] --> Query Service --> Model Cache --> 추론 결과 반환

**Event Sourcing:**

상태 변경을 이벤트로 기록합니다. 모델 서빙에서는 모델 배포 이력, A/B 테스트 결과 등을 이벤트로 관리할 수 있습니다.

Event 1: ModelDeployed(v1.0, timestamp, config)

Event 2: TrafficSplit(v1.0=90%, v1.1=10%)

Event 3: ModelPromoted(v1.1, reason="A/B test passed")

Event 4: ModelDeprecated(v1.0)

**Saga Pattern:**

분산 트랜잭션을 관리하는 패턴입니다. 예를 들어 모델 배포 프로세스에서 활용합니다.

Step 1: 모델 파일 업로드 → 성공

Step 2: 설정 파일 업데이트 → 성공

Step 3: 카나리 배포 시작 → 실패!

→ 보상 트랜잭션: Step 2 롤백 → Step 1 롤백

API Design: REST vs gRPC vs GraphQL

**REST API:**

- 범용적이고 클라이언트(웹/앱)와의 통신에 적합

- OpenAPI(Swagger) 명세를 통한 문서화가 용이

- JSON 기반으로 디버깅이 쉬움

**gRPC:**

- 서비스 간 내부 통신에 최적

- Protocol Buffers 기반으로 직렬화/역직렬화 성능이 우수

- 양방향 스트리밍 지원

- ML 모델 서빙에서 자주 사용 (Triton의 기본 프로토콜)

syntax = "proto3";

service ModelServing {

rpc Predict(PredictRequest) returns (PredictResponse);

rpc StreamPredict(stream PredictRequest) returns (stream PredictResponse);

rpc GetModelStatus(ModelStatusRequest) returns (ModelStatusResponse);

}

message PredictRequest {

string model_name = 1;

string model_version = 2;

repeated float features = 3;

}

**GraphQL:**

- 클라이언트가 필요한 데이터만 정확히 요청 가능

- 모델 메타데이터 조회 등에 활용 가능

**추천 전략:** 외부 API는 REST, 내부 서비스 간 통신은 gRPC, 메타데이터 조회는 GraphQL

인증/인가

- **OAuth2**: 토큰 기반 인증/인가 프레임워크

- **JWT (JSON Web Token)**: 상태를 서버에 저장하지 않는 토큰 방식

- **mTLS (mutual TLS)**: 서비스 간 상호 인증 (Service Mesh에서 자동 적용)

- **API Key**: 간단한 서비스 인증에 사용

캐싱 전략

ML 서빙에서 캐싱은 성능 최적화의 핵심입니다.

[요청] → Cache Hit? → YES → 캐시된 결과 반환 (1ms 이하)

→ NO → 모델 추론 수행 → 결과 캐싱 → 반환 (50~100ms)

**캐싱 레이어:**

- **L1 Cache (Application)**: 인메모리 캐시 (예: Python의 lru_cache)

- **L2 Cache (Redis/Memcached)**: 분산 캐시, 서비스 인스턴스 간 공유

- **L3 Cache (CDN)**: 정적 콘텐츠나 변하지 않는 추론 결과

**Redis 활용 패턴:**

class InferenceCache:

def __init__(self, redis_url: str, ttl: int = 300):

self.redis = redis.from_url(redis_url)

self.ttl = ttl

async def get_or_compute(

self, cache_key: str, compute_fn

):

캐시 조회

cached = await self.redis.get(cache_key)

if cached:

return json.loads(cached)

추론 수행

result = await compute_fn()

결과 캐싱

await self.redis.setex(

cache_key, self.ttl, json.dumps(result)

)

return result

메시지 큐

비동기 통신과 이벤트 기반 아키텍처의 핵심 인프라입니다.

**Kafka:**

- 대용량 이벤트 스트리밍에 최적

- 모델 추론 결과 로깅, 피처 파이프라인에 활용

- 높은 처리량과 내구성

- 파티셔닝을 통한 병렬 처리

**사용 시나리오:**

- 비동기 배치 추론 요청 처리

- 모델 학습 데이터 파이프라인

- 실시간 피처 업데이트

- 이벤트 기반 모델 재학습 트리거

Database

**PostgreSQL:**

- 모델 메타데이터, 실험 결과, 사용자 데이터 저장

- JSON 컬럼으로 유연한 스키마 지원

- 성능 최적화: 인덱싱, 파티셔닝, 커넥션 풀링(PgBouncer)

**MongoDB:**

- 모델 설정, 피처 정의 등 비정형 데이터에 적합

- 문서 기반이라 스키마 변경이 자유로움

**Redis:**

- 실시간 피처 서빙

- 세션 관리, 속도 제한 카운터

- 모델 추론 결과 캐싱

3-3. ML 모델 서빙

ML Backend Engineer의 핵심 전문 영역입니다. 이 섹션은 특히 깊이 있게 학습해야 합니다.

Triton Inference Server (NVIDIA)

가장 널리 사용되는 프로덕션 레벨 모델 서빙 프레임워크입니다.

**핵심 기능:**

- 다중 프레임워크 지원 (TensorFlow, PyTorch, ONNX, TensorRT)

- Dynamic Batching: 여러 요청을 자동으로 배치로 묶어 처리

- Model Pipeline: 여러 모델을 순차적으로 실행

- 모델 앙상블: 여러 모델의 결과를 조합

- GPU/CPU 동시 서빙

- 모델 핫 리로드 (무중단 모델 업데이트)

**모델 저장소 구조:**

model_repository/

credit_score/

config.pbtxt

1/

model.onnx

2/

model.onnx

fds_detector/

config.pbtxt

1/

model.plan

**config.pbtxt 예시:**

name: "credit_score"

platform: "onnxruntime_onnx"

max_batch_size: 64

input [

{

name: "features"

data_type: TYPE_FP32

dims: [ 128 ]

}

]

output [

{

name: "score"

data_type: TYPE_FP32

dims: [ 1 ]

}

]

dynamic_batching {

preferred_batch_size: [ 16, 32 ]

max_queue_delay_microseconds: 5000

}

instance_group [

{

count: 2

kind: KIND_GPU

gpus: [ 0 ]

}

]

TorchServe / TensorFlow Serving

**TorchServe:**

- PyTorch 모델 전용 서빙 프레임워크

- 커스텀 핸들러를 통한 전/후처리 로직 구현

- 모델 버전 관리 기본 지원

**TensorFlow Serving:**

- TensorFlow/Keras 모델 전용

- SavedModel 포맷 지원

- gRPC, REST 인터페이스 제공

BentoML, Ray Serve, Seldon Core

**BentoML:**

- Python 네이티브 모델 패키징 프레임워크

- 간단한 데코레이터로 모델 서빙 API 생성

- 컨테이너화 자동화

from bentoml.io import JSON

runner = bentoml.onnx.get("credit_score:latest").to_runner()

svc = bentoml.Service("credit-scoring", runners=[runner])

@svc.api(input=JSON(), output=JSON())

async def predict(input_data: dict) -> dict:

features = input_data["features"]

result = await runner.predict.async_run(features)

return {"score": float(result[0])}

**Ray Serve:**

- Ray 기반 분산 모델 서빙

- 파이프라인 구성이 유연

- 오토스케일링 기본 지원

- 여러 모델을 하나의 서빙 그래프로 구성 가능

**Seldon Core:**

- Kubernetes 네이티브 ML 서빙 플랫폼

- A/B 테스트, 카나리 배포 기본 지원

- 모델 설명(Explainability) 기능 내장

- 다양한 추론 그래프 패턴 지원

모델 최적화

**ONNX (Open Neural Network Exchange):**

- 프레임워크 간 모델 호환성을 위한 표준 포맷

- PyTorch, TensorFlow 등에서 변환 가능

- ONNX Runtime으로 최적화된 추론

PyTorch 모델을 ONNX로 변환

dummy_input = torch.randn(1, 128)

torch.onnx.export(

model, dummy_input, "credit_score.onnx",

input_names=["features"],

output_names=["score"],

dynamic_axes={"features": {0: "batch_size"}},

)

**TensorRT:**

- NVIDIA GPU 전용 최적화 엔진

- 레이어 융합, 커널 자동 튜닝 등으로 추론 속도 2~5배 향상

- INT8/FP16 양자화 지원

**양자화 (Quantization):**

- FP32 → FP16: 메모리 절반, 속도 약 2배 향상

- FP32 → INT8: 메모리 1/4, 속도 약 3~4배 향상

- 정확도 손실을 최소화하면서 성능을 극대화

Feature Store

ML 모델이 추론을 수행하려면 입력 피처가 필요합니다. Feature Store는 이 피처를 중앙에서 관리합니다.

**Feast (Feature Store):**

- 오프라인 스토어: 학습용 피처 (BigQuery, S3 등)

- 온라인 스토어: 실시간 서빙용 피처 (Redis, DynamoDB)

- 피처 정의를 코드로 관리 (Feature Definition as Code)

from feast import Entity, FeatureView, Field

from feast.types import Float32, String

user = Entity(

name="user_id",

description="은행 고객 ID",

)

user_features = FeatureView(

name="user_credit_features",

entities=[user],

schema=[

Field(name="avg_balance_30d", dtype=Float32),

Field(name="transaction_count_7d", dtype=Float32),

Field(name="credit_utilization", dtype=Float32),

Field(name="payment_history_score", dtype=Float32),

],

online=True,

source=user_credit_source,

)

A/B Testing 프레임워크

새로운 모델을 배포할 때 기존 모델과 비교 실험을 수행합니다.

사용자 요청 → 트래픽 분배기 → 80% → 모델 v1 (기존)

→ 20% → 모델 v2 (신규)

→ 결과 비교 분석 → 승자 결정

**핵심 고려사항:**

- 통계적 유의성 확보 (p-value, 신뢰 구간)

- 사용자 경험 일관성 (같은 사용자는 같은 모델로)

- 실시간 모니터링 (조기 종료 기준 설정)

- 비즈니스 메트릭과 모델 메트릭 동시 추적

3-4. Kubernetes 운영

K8s 아키텍처 기초

**핵심 리소스:**

Deployment: ML 서빙 서버 배포

apiVersion: apps/v1

kind: Deployment

metadata:

name: credit-score-serving

namespace: ml-serving

spec:

replicas: 3

selector:

matchLabels:

app: credit-score

template:

metadata:

labels:

app: credit-score

spec:

containers:

- name: triton

image: nvcr.io/nvidia/tritonserver:23.10-py3

ports:

- containerPort: 8000

name: http

- containerPort: 8001

name: grpc

resources:

requests:

cpu: '2'

memory: '4Gi'

nvidia.com/gpu: '1'

limits:

cpu: '4'

memory: '8Gi'

nvidia.com/gpu: '1'

readinessProbe:

httpGet:

path: /v2/health/ready

port: 8000

initialDelaySeconds: 30

periodSeconds: 10

livenessProbe:

httpGet:

path: /v2/health/live

port: 8000

initialDelaySeconds: 30

periodSeconds: 15

Service: 내부 통신용 ClusterIP

apiVersion: v1

kind: Service

metadata:

name: credit-score-service

spec:

selector:

app: credit-score

ports:

- name: http

port: 8000

targetPort: 8000

- name: grpc

port: 8001

targetPort: 8001

type: ClusterIP

Ingress: 외부 트래픽 라우팅

apiVersion: networking.k8s.io/v1

kind: Ingress

metadata:

name: ml-serving-ingress

annotations:

nginx.ingress.kubernetes.io/rewrite-target: /

spec:

rules:

- host: ml-serving.tossbank.internal

http:

paths:

- path: /credit-score

pathType: Prefix

backend:

service:

name: credit-score-service

port:

number: 8000

오토스케일링

**HPA (Horizontal Pod Autoscaler):**

apiVersion: autoscaling/v2

kind: HorizontalPodAutoscaler

metadata:

name: credit-score-hpa

spec:

scaleTargetRef:

apiVersion: apps/v1

kind: Deployment

name: credit-score-serving

minReplicas: 2

maxReplicas: 20

metrics:

- type: Resource

resource:

name: cpu

target:

type: Utilization

averageUtilization: 70

- type: Pods

pods:

metric:

name: inference_requests_per_second

target:

type: AverageValue

averageValue: '100'

behavior:

scaleUp:

stabilizationWindowSeconds: 60

policies:

- type: Percent

value: 100

periodSeconds: 60

scaleDown:

stabilizationWindowSeconds: 300

policies:

- type: Percent

value: 10

periodSeconds: 60

**KEDA (Kubernetes Event-Driven Autoscaling):**

- Kafka 큐 길이, Prometheus 메트릭 등을 기반으로 스케일링

- 0으로 스케일 다운 가능 (비용 절약)

- 이벤트 기반 배치 추론에 적합

Helm Charts & Kustomize

**Helm:**

- Kubernetes 리소스를 패키지로 관리

- 환경별(dev/staging/prod) 값 분리

- 차트 저장소를 통한 버전 관리

**Kustomize:**

- 베이스 설정 + 오버레이로 환경별 관리

- YAML 패치 방식으로 직관적

- kubectl에 기본 내장

Service Mesh

**Istio:**

- 서비스 간 mTLS 자동 적용

- 트래픽 라우팅 (카나리 배포, A/B 테스트)

- 서킷 브레이커, 재시도, 타임아웃 정책

- 분산 추적 자동 주입

VirtualService: 카나리 배포 트래픽 분배

apiVersion: networking.istio.io/v1beta1

kind: VirtualService

metadata:

name: credit-score-routing

spec:

hosts:

- credit-score-service

http:

- route:

- destination:

host: credit-score-service

subset: stable

weight: 90

- destination:

host: credit-score-service

subset: canary

weight: 10

GitOps: ArgoCD

ArgoCD Application 정의

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: credit-score-serving

namespace: argocd

spec:

project: ml-serving

source:

repoURL: https://github.com/tossbank/ml-serving-manifests

targetRevision: main

path: credit-score/overlays/production

destination:

server: https://kubernetes.default.svc

namespace: ml-serving

syncPolicy:

automated:

prune: true

selfHeal: true

syncOptions:

- CreateNamespace=true

**GitOps 워크플로:**

코드 변경 → Git Push → ArgoCD 감지 → 자동 배포 → 상태 검증

→ 실패 시 자동 롤백

GPU Scheduling on K8s

ML 모델 서빙에서 GPU 관리는 핵심 과제입니다.

**GPU 리소스 요청:**

resources:

limits:

nvidia.com/gpu: 1 # GPU 1개 할당

**Multi-Instance GPU (MIG):**

- 하나의 물리 GPU를 여러 인스턴스로 분할

- 작은 모델 여러 개를 하나의 GPU에서 동시 서빙

- 비용 효율성 극대화

**GPU Node Pool:**

- GPU 노드와 CPU 노드를 분리하여 관리

- 모델 추론은 GPU 노드, 전/후처리는 CPU 노드

- 노드 어피니티(Affinity)를 통한 스케줄링 제어

3-5. MSA & 분산 추적

OpenTelemetry

분산 추적, 메트릭, 로그를 통합하는 표준 프레임워크입니다.

**Python에서의 계측:**

from opentelemetry import trace

from opentelemetry.sdk.trace import TracerProvider

from opentelemetry.sdk.trace.export import BatchSpanProcessor

from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (

OTLPSpanExporter,

)

트레이서 설정

provider = TracerProvider()

processor = BatchSpanProcessor(

OTLPSpanExporter(endpoint="http://otel-collector:4317")

)

provider.add_span_processor(processor)

trace.set_tracer_provider(provider)

tracer = trace.get_tracer("ml-serving")

async def predict(request):

with tracer.start_as_current_span("predict") as span:

span.set_attribute("model.name", request.model_name)

span.set_attribute("model.version", request.model_version)

with tracer.start_as_current_span("feature_fetch"):

features = await fetch_features(request.user_id)

with tracer.start_as_current_span("model_inference"):

result = await run_inference(features)

span.set_attribute("inference.latency_ms", result.latency)

return result

Prometheus + Grafana

**주요 메트릭:**

from prometheus_client import (

Counter, Histogram, Gauge, start_http_server

)

추론 요청 수

INFERENCE_REQUESTS = Counter(

"inference_requests_total",

"Total inference requests",

["model_name", "model_version", "status"]

)

추론 지연시간

INFERENCE_LATENCY = Histogram(

"inference_latency_seconds",

"Inference latency in seconds",

["model_name"],

buckets=[0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0]

)

활성 모델 수

ACTIVE_MODELS = Gauge(

"active_models",

"Number of actively serving models"

)

GPU 사용률

GPU_UTILIZATION = Gauge(

"gpu_utilization_percent",

"GPU utilization percentage",

["gpu_id"]

)

**Grafana 대시보드 구성:**

- **서비스 헬스 패널**: 요청률(RPS), 에러율, P50/P95/P99 지연시간

- **모델 성능 패널**: 모델별 추론 시간, 배치 크기 분포

- **인프라 패널**: CPU/GPU/메모리 사용률, 파드 상태

- **비즈니스 패널**: 모델 정확도 모니터링, A/B 테스트 결과

로그 수집 및 분석

**구조화된 로깅:**

logger = structlog.get_logger()

async def predict(request):

logger.info(

"inference_started",

model_name=request.model_name,

user_id=request.user_id,

request_id=request.request_id,

)

try:

result = await run_inference(request)

logger.info(

"inference_completed",

model_name=request.model_name,

latency_ms=result.latency_ms,

score=result.score,

)

return result

except Exception as e:

logger.error(

"inference_failed",

model_name=request.model_name,

error=str(e),

error_type=type(e).__name__,

)

raise

**ELK Stack vs Loki:**

- **ELK Stack** (Elasticsearch + Logstash + Kibana): 전문(Full-text) 검색에 강점, 대규모 로그 분석에 적합

- **Loki** (Grafana): 라벨 기반 로그 집계, Grafana와 네이티브 통합, 비용 효율적

Alerting

**알림 전략:**

- **P1 (즉시 대응)**: 서비스 다운, 에러율 급증, 데이터 유실

- **P2 (30분 내 대응)**: 지연시간 SLA 위반, 디스크 사용률 90% 초과

- **P3 (업무 시간 내 대응)**: 메모리 사용률 증가 추세, 모델 성능 저하

Prometheus AlertManager 규칙 예시

groups:

- name: ml-serving-alerts

rules:

- alert: HighInferenceLatency

expr: |

histogram_quantile(0.99,

rate(inference_latency_seconds_bucket[5m])

) > 0.1

for: 5m

labels:

severity: warning

annotations:

summary: 'P99 추론 지연시간이 100ms를 초과했습니다'

- alert: HighErrorRate

expr: |

rate(inference_requests_total{status="error"}[5m])

/ rate(inference_requests_total[5m]) > 0.01

for: 2m

labels:

severity: critical

annotations:

summary: '추론 에러율이 1%를 초과했습니다'

3-6. 대규모 트래픽 & SLA

Load Balancing

**L4 (Transport Layer):**

- TCP/UDP 레벨에서 트래픽 분배

- 매우 빠른 처리 속도

- IP + Port 기반 라우팅

**L7 (Application Layer):**

- HTTP 헤더, URL 경로 기반 라우팅

- gRPC, WebSocket 지원

- 모델 이름에 따른 라우팅 가능

**알고리즘:**

- **Round Robin**: 순차적 분배 (기본)

- **Least Connections**: 연결 수가 가장 적은 서버로

- **Weighted Round Robin**: 서버 성능에 따라 가중치 부여

- **Consistent Hashing**: 같은 사용자를 같은 서버로 (캐시 효율)

Rate Limiting

**Token Bucket 알고리즘:**

class TokenBucket:

def __init__(self, rate: float, capacity: int):

self.rate = rate # 초당 토큰 생성 속도

self.capacity = capacity

self.tokens = capacity

self.last_refill = time.monotonic()

self.lock = asyncio.Lock()

async def acquire(self) -> bool:

async with self.lock:

now = time.monotonic()

elapsed = now - self.last_refill

self.tokens = min(

self.capacity,

self.tokens + elapsed * self.rate

)

self.last_refill = now

if self.tokens >= 1:

self.tokens -= 1

return True

return False

**Sliding Window 알고리즘:**

- 고정 윈도우의 경계 효과를 해결

- Redis ZSET을 활용한 분산 환경 구현

- 더 정밀한 속도 제한 가능

Circuit Breaker

from enum import Enum

from dataclasses import dataclass

class CircuitState(Enum):

CLOSED = "closed" # 정상 상태

OPEN = "open" # 차단 상태

HALF_OPEN = "half_open" # 복구 확인 중

@dataclass

class CircuitBreaker:

failure_threshold: int = 5

recovery_timeout: float = 30.0

state: CircuitState = CircuitState.CLOSED

failure_count: int = 0

last_failure_time: float = 0

async def call(self, func, *args, **kwargs):

if self.state == CircuitState.OPEN:

if time.monotonic() - self.last_failure_time > self.recovery_timeout:

self.state = CircuitState.HALF_OPEN

else:

raise CircuitOpenError("Circuit is open")

try:

result = await func(*args, **kwargs)

if self.state == CircuitState.HALF_OPEN:

self.state = CircuitState.CLOSED

self.failure_count = 0

return result

except Exception as e:

self.failure_count += 1

self.last_failure_time = time.monotonic()

if self.failure_count >= self.failure_threshold:

self.state = CircuitState.OPEN

raise

성능 테스트

**k6 로드 테스트 스크립트:**

export const options = {

stages: [

{ duration: '2m', target: 100 }, // 점진적 증가

{ duration: '5m', target: 1000 }, // 피크 부하

{ duration: '2m', target: 0 }, // 점진적 감소

],

thresholds: {

http_req_duration: ['p(99)<100'], // P99 100ms 이하

http_req_failed: ['rate<0.01'], // 에러율 1% 미만

},

}

export default function () {

const payload = JSON.stringify({

user_id: `user_${__VU}`,

features: Array.from({ length: 128 }, () => Math.random()),

})

const params = {

headers: { 'Content-Type': 'application/json' },

}

const res = http.post('http://ml-serving.internal/v1/predict', payload, params)

check(res, {

'status is 200': (r) => r.status === 200,

'latency < 100ms': (r) => r.timings.duration < 100,

})

}

**Locust 파이썬 기반 테스트:**

from locust import HttpUser, task, between

class MLServingUser(HttpUser):

wait_time = between(0.1, 0.5)

@task(weight=10)

def predict_credit_score(self):

self.client.post("/v1/predict", json={

"model_name": "credit_score",

"user_id": "test_user",

"features": [0.5] * 128,

})

@task(weight=5)

def predict_fds(self):

self.client.post("/v1/predict", json={

"model_name": "fds_detector",

"transaction_id": "txn_123",

"features": [0.3] * 64,

})

4. 면접 예상 질문 30선

서버 아키텍처 (10문항)

**Q1. REST API와 gRPC의 차이점을 설명하고, ML 모델 서빙에서 어떤 것을 선택하겠습니까?**

핵심 포인트: gRPC는 Protocol Buffers 기반으로 직렬화 성능이 우수하고, 양방향 스트리밍을 지원하므로 내부 서비스 간 통신에 적합합니다. 외부 클라이언트 API는 REST로, 내부 모델 서빙은 gRPC로 구성하는 것이 일반적입니다.

**Q2. CQRS 패턴을 ML 서빙 시스템에 어떻게 적용할 수 있습니까?**

핵심 포인트: 모델 배포(Command)와 추론(Query)를 분리합니다. Command 측은 모델 레지스트리 업데이트, 설정 변경을 담당하고, Query 측은 읽기 전용으로 최적화된 추론 서비스를 운영합니다.

**Q3. 서킷 브레이커의 세 가지 상태(CLOSED, OPEN, HALF_OPEN)를 설명하고, ML 서빙에서의 활용 사례를 들어주세요.**

핵심 포인트: Feature Store 장애 시 캐시된 피처를 사용하거나, 외부 모델 서비스 장애 시 폴백 모델로 전환하는 등의 사례를 설명합니다.

**Q4. 동기 통신과 비동기 통신의 트레이드오프를 설명하고, 각각 어떤 상황에서 사용하겠습니까?**

핵심 포인트: 실시간 추론은 동기(gRPC/REST), 배치 추론이나 로깅은 비동기(Kafka)로 처리합니다. 비동기 통신은 서비스 간 결합도를 낮추고 장애 전파를 방지합니다.

**Q5. 캐싱 전략에서 Cache Invalidation 문제를 어떻게 해결하겠습니까?**

핵심 포인트: TTL 기반 만료, 이벤트 기반 무효화, Write-through/Write-behind 패턴 등을 설명합니다. ML 서빙에서는 모델 업데이트 시 관련 캐시를 이벤트로 무효화합니다.

**Q6. Connection Pooling이 왜 중요하고, 어떻게 구현하겠습니까?**

핵심 포인트: DB 커넥션, gRPC 채널, HTTP 커넥션 등의 생성 비용을 줄이고, 리소스를 효율적으로 관리합니다. 풀 크기 설정이 중요합니다 (너무 작으면 병목, 너무 크면 리소스 낭비).

**Q7. API 버전 관리 전략을 설명해주세요.**

핵심 포인트: URL 경로 기반(/v1/predict, /v2/predict), 헤더 기반 등의 전략이 있습니다. 하위 호환성을 유지하면서 점진적으로 새 버전으로 마이그레이션합니다.

**Q8. Saga 패턴의 두 가지 구현 방식(Choreography vs Orchestration)의 차이는 무엇입니까?**

핵심 포인트: Choreography는 이벤트 기반으로 각 서비스가 자율적으로 동작하고, Orchestration은 중앙 조율자가 흐름을 제어합니다. 복잡한 워크플로에는 Orchestration이 적합합니다.

**Q9. 데이터베이스 인덱싱 전략을 설명하고, 추론 로그 테이블에 어떤 인덱스를 설계하겠습니까?**

핵심 포인트: B-Tree, Hash, GIN 인덱스의 차이를 설명합니다. 추론 로그는 timestamp, model_name, user_id 등에 복합 인덱스를 설정하고 파티셔닝을 적용합니다.

**Q10. 마이크로서비스 간 데이터 일관성을 어떻게 보장하겠습니까?**

핵심 포인트: 강한 일관성(분산 트랜잭션)보다 최종적 일관성(Eventual Consistency)을 선택하는 것이 일반적입니다. Outbox 패턴, CDC(Change Data Capture) 등을 활용합니다.

K8s & 인프라 (10문항)

**Q11. Pod의 라이프사이클과 Probe(readinessProbe, livenessProbe, startupProbe)의 차이를 설명해주세요.**

핵심 포인트: livenessProbe는 컨테이너 재시작 여부 결정, readinessProbe는 트래픽 수신 가능 여부 결정, startupProbe는 초기화 완료 여부 결정입니다. ML 서빙에서 모델 로딩 시간이 긴 경우 startupProbe가 중요합니다.

**Q12. HPA와 VPA의 차이점과 각각의 적합한 사용 사례는 무엇입니까?**

핵심 포인트: HPA는 파드 수를 조절(수평 확장), VPA는 파드의 리소스 요청을 조절(수직 확장)합니다. ML 서빙은 HPA를 기본으로 사용하고, GPU 리소스 최적화에 VPA를 보조적으로 사용합니다.

**Q13. Kubernetes에서 무중단 배포(Zero-Downtime Deployment)를 어떻게 구현하겠습니까?**

핵심 포인트: Rolling Update 전략, readinessProbe 설정, PodDisruptionBudget 설정, Graceful Shutdown(preStop hook) 구현을 설명합니다.

**Q14. Helm Chart와 Kustomize의 차이점은 무엇이고, 어떤 상황에서 각각을 사용하겠습니까?**

핵심 포인트: Helm은 템플릿 기반 패키징으로 복잡한 애플리케이션 배포에 적합하고, Kustomize는 YAML 패치 기반으로 단순한 환경별 설정 관리에 적합합니다.

**Q15. Service Mesh(Istio)가 ML 서빙에 제공하는 이점은 무엇입니까?**

핵심 포인트: mTLS 자동 적용, 트래픽 관리(카나리 배포, A/B 테스트), 서킷 브레이커, 분산 추적 자동 주입 등을 설명합니다.

**Q16. GitOps(ArgoCD)의 원칙과 장점을 설명해주세요.**

핵심 포인트: Git을 single source of truth로 사용하여 선언적 배포를 관리합니다. 감사 추적, 롤백 용이성, 재현 가능성이 핵심 장점입니다.

**Q17. Kubernetes에서 GPU를 효율적으로 관리하는 방법은 무엇입니까?**

핵심 포인트: NVIDIA Device Plugin, MIG(Multi-Instance GPU), GPU 타임셰어링, 노드 어피니티를 통한 GPU 노드 전용 스케줄링을 설명합니다.

**Q18. Pod 스케줄링에서 Affinity, Taint, Toleration의 차이를 설명해주세요.**

핵심 포인트: Node Affinity는 특정 노드에 스케줄링을 선호하고, Taint/Toleration은 특정 노드를 특정 워크로드에 예약합니다. GPU 노드에 ML 서빙 파드만 스케줄링하는 등에 활용합니다.

**Q19. ConfigMap과 Secret의 차이점과 보안 관련 고려사항은 무엇입니까?**

핵심 포인트: Secret은 base64 인코딩(암호화 아님), RBAC으로 접근 제어, etcd 암호화 설정, External Secrets Operator를 통한 외부 비밀 관리 도구 연동을 설명합니다.

**Q20. Kubernetes의 리소스 요청(Requests)과 제한(Limits)을 어떻게 설정하겠습니까?**

핵심 포인트: Requests는 스케줄링 기준, Limits는 최대 사용량 제한입니다. ML 서빙에서는 GPU 리소스의 정확한 설정이 중요하며, CPU/메모리는 프로파일링을 통해 적정값을 찾습니다.

ML 서빙 & 시스템 설계 (10문항)

**Q21. 실시간 신용평가 모델 서빙 시스템을 설계해주세요.**

핵심 포인트: API Gateway → Feature Store 조회 → 모델 추론 → 결과 반환의 플로우를 설계합니다. P99 100ms SLA, 99.99% 가용성, 무중단 모델 업데이트를 충족하는 아키텍처를 제시합니다.

**Q22. Dynamic Batching이 무엇이고, 어떤 트레이드오프가 있습니까?**

핵심 포인트: 여러 요청을 모아서 배치로 처리하면 GPU 활용률이 높아지지만, 개별 요청의 지연시간이 증가할 수 있습니다. max_queue_delay로 최대 대기 시간을 설정합니다.

**Q23. 모델 A/B 테스트를 어떻게 설계하고 운영하겠습니까?**

핵심 포인트: 트래픽 분배(해시 기반), 통계적 유의성 검정, 조기 종료 기준, 안전 가드레일(에러율 급증 시 자동 롤백) 등을 설명합니다.

**Q24. ONNX와 TensorRT를 활용한 모델 최적화 과정을 설명해주세요.**

핵심 포인트: PyTorch 모델 → ONNX 변환 → ONNX 최적화 → TensorRT 엔진 생성 → 벤치마크 → 정확도 검증의 과정을 설명합니다.

**Q25. Feature Store의 온라인/오프라인 구분과 각각의 역할은 무엇입니까?**

핵심 포인트: 오프라인은 학습용(대용량, 배치 처리), 온라인은 서빙용(저지연, 실시간 조회)입니다. Feature Consistency(학습과 서빙 시 동일한 피처 보장)가 핵심 과제입니다.

**Q26. 이상거래탐지(FDS) 시스템의 아키텍처를 설계해주세요.**

핵심 포인트: 실시간 스트리밍(Kafka) → 피처 엔지니어링 → ML 추론 → 알림/차단의 파이프라인입니다. 초당 수만 건 처리, 밀리초 단위 응답, 높은 재현율(Recall)이 요구됩니다.

**Q27. 카나리 배포와 블루-그린 배포의 차이점과 각각의 장단점은 무엇입니까?**

핵심 포인트: 카나리는 점진적 트래픽 전환(위험 최소화), 블루-그린은 즉시 전환(빠른 배포/롤백). ML 모델 서빙에서는 카나리 배포가 일반적입니다(모델 성능을 점진적으로 검증).

**Q28. P99 지연시간이 급증했을 때 어떻게 디버깅하겠습니까?**

핵심 포인트: 분산 추적으로 병목 구간 확인 → 메트릭으로 리소스 사용률 확인 → 로그로 에러/경고 확인 → 프로파일링으로 코드 레벨 원인 분석의 순서로 접근합니다.

**Q29. LLM 기반 AI 챗봇의 서빙 아키텍처를 설계해주세요.**

핵심 포인트: RAG(Retrieval-Augmented Generation) 아키텍처, 벡터 DB 활용, GPU 메모리 관리, 스트리밍 응답, 토큰 레벨 속도 제한 등을 포함합니다.

**Q30. ML 모델의 모니터링 전략을 설계해주세요. 모델 드리프트를 어떻게 감지하겠습니까?**

핵심 포인트: 입력 데이터 분포 변화(Data Drift), 모델 예측 분포 변화(Concept Drift)를 모니터링합니다. KS Test, PSI(Population Stability Index) 등의 통계 기법을 활용합니다.

5. 6개월 학습 로드맵

월별 상세 계획

| 월 | 주제 | 구체적 목표 |

| ----- | ----------------------------- | ------------------------------------------------- |

| 1개월 | 언어 선택 + 서버 기초 | FastAPI 또는 Spring Boot로 REST API 프로젝트 완성 |

| 2개월 | DB + 캐시 + 메시지 큐 | Redis, PostgreSQL, Kafka 실습 프로젝트 |

| 3개월 | K8s + 배포 | Minikube에서 EKS/GKE로, Helm 차트 작성 |

| 4개월 | ML 서빙 기초 | Triton, BentoML로 실제 모델 서빙 구현 |

| 5개월 | MSA + 분산 추적 | OpenTelemetry, Grafana 대시보드 구성 |

| 6개월 | 시스템 설계 면접 + 포트폴리오 | 모의면접 실전, 이력서 최종 완성 |

1개월차: 언어 선택 + 서버 기초

**주차별 계획:**

Week 1-2: 메인 언어 기초 다지기

- Python 선택 시: FastAPI 공식 튜토리얼 완주

- Kotlin 선택 시: Spring Boot + Kotlin 기본 프로젝트

- 기본 CRUD API 개발 (모델 메타데이터 관리 API)

Week 3-4: 비동기 프로그래밍 + 테스트

- asyncio/Coroutines/goroutine 심화 학습

- 단위 테스트, 통합 테스트 작성

- Docker로 개발 환경 구성

**이달의 산출물:** 모델 메타데이터 관리 REST API (GitHub에 공개)

2개월차: DB + 캐시 + 메시지 큐

**주차별 계획:**

Week 1-2: 데이터베이스 심화

- PostgreSQL: 스키마 설계, 인덱싱, 쿼리 최적화

- Redis: 캐싱 패턴, 데이터 구조 활용

- SQLAlchemy/Exposed ORM 사용법

Week 3-4: 메시지 큐 + 이벤트 기반 아키텍처

- Kafka 기초: Producer, Consumer, Topic, Partition

- 이벤트 기반 비동기 처리 구현

- docker-compose로 통합 환경 구성

**이달의 산출물:** 1개월차 프로젝트에 DB, 캐시, 비동기 이벤트 처리 추가

3개월차: K8s + 배포

**주차별 계획:**

Week 1-2: Kubernetes 기초

- Minikube로 로컬 클러스터 구성

- Pod, Deployment, Service, Ingress 실습

- ConfigMap, Secret 관리

Week 3-4: 배포 자동화

- Helm Chart 작성

- ArgoCD로 GitOps 배포 구현

- HPA 오토스케일링 설정

- CI/CD 파이프라인 (GitHub Actions)

**이달의 산출물:** K8s에 배포된 애플리케이션 + Helm Chart + ArgoCD 설정

4개월차: ML 서빙 기초

**주차별 계획:**

Week 1-2: 모델 서빙 기초

- Triton Inference Server 설치 및 기본 사용

- ONNX 모델 변환 실습

- BentoML로 간단한 모델 서빙

Week 3-4: 서빙 최적화

- Dynamic Batching 설정 및 벤치마크

- 모델 버전 관리 구현

- Feature Store(Feast) 기초 설정

- K8s에 Triton 배포

**이달의 산출물:** K8s 위에서 동작하는 ML 모델 서빙 파이프라인

5개월차: MSA + 분산 추적

**주차별 계획:**

Week 1-2: Observability 구축

- OpenTelemetry 계측 구현

- Prometheus + Grafana 모니터링 대시보드

- Jaeger로 분산 추적 시각화

Week 3-4: MSA 패턴 적용

- 서킷 브레이커 구현

- 서비스 간 gRPC 통신

- 알림(Alerting) 규칙 설정

- 성능 테스트(k6/Locust) 실행

**이달의 산출물:** 완전한 Observability 스택이 갖추어진 ML 서빙 시스템

6개월차: 시스템 설계 면접 + 포트폴리오

**주차별 계획:**

Week 1-2: 시스템 설계 연습

- 면접 예상 질문 30선 모두 연습

- 화이트보드 시스템 설계 연습

- 동료/스터디 그룹과 모의면접

Week 3-4: 포트폴리오 + 이력서

- GitHub 프로젝트 README 정비

- 기술 블로그 작성 (학습 과정 기록)

- 이력서 작성 및 리뷰

- 토스뱅크 외 관심 기업 지원 준비

**이달의 산출물:** 완성된 이력서 + 포트폴리오 + 모의면접 피드백

6. 이력서 작성 전략

STAR 기법으로 경험 정리

이력서에서 가장 중요한 것은 **"무엇을 했는가"가 아니라 "어떤 문제를 어떻게 해결했는가"**입니다.

**STAR 프레임워크:**

- **S (Situation)**: 어떤 상황이었나

- **T (Task)**: 어떤 과제가 주어졌나

- **A (Action)**: 구체적으로 무엇을 했나

- **R (Result)**: 어떤 결과를 만들었나

**좋은 예시:**

[프로젝트] ML 모델 서빙 플랫폼 구축

상황: 데이터팀이 학습한 모델을 프로덕션에 배포하는 데 평균 2주가 소요

과제: 모델 배포 시간을 단축하고 서빙 안정성을 확보

행동:

- FastAPI + Triton 기반 모델 서빙 API 개발

- Helm Chart로 K8s 배포 자동화

- ArgoCD GitOps 파이프라인 구축

- OpenTelemetry 기반 모니터링 대시보드 구성

결과:

- 모델 배포 시간 2주 → 30분으로 단축 (97% 감소)

- P99 추론 지연시간 50ms 달성

- 서비스 가용성 99.95% 유지

트레이드오프 분석 강조

면접관이 가장 보고 싶어하는 것은 **기술적 의사결정 과정**입니다.

**작성 팁:**

- "A 대신 B를 선택한 이유"를 명확히 기술

- 고려했던 대안과 각각의 장단점을 언급

- 성능, 비용, 운영 복잡성 등 다차원적 비교

**예시:**

gRPC를 서비스 간 통신 프로토콜로 선택

- REST 대비 직렬화 성능 3배 향상 확인

- 단, 디버깅 복잡성 증가를 고려하여 gRPC 리플렉션과

grpcurl을 활용한 디버깅 환경 구축

- HTTP/2 기반 다중화로 커넥션 관리 효율화

비즈니스 임팩트를 수치로 증명

**수치화 가이드:**

- 성능 개선: "P99 지연시간 200ms에서 50ms로 75% 감소"

- 비용 절감: "GPU 활용률 최적화로 월 클라우드 비용 30% 절감"

- 효율성: "모델 배포 자동화로 엔지니어 시간 주당 10시간 절약"

- 안정성: "서비스 가용성 99.9%에서 99.99%로 향상"

모니터링에서 개선까지의 사이클 보여주기

단순히 "만들었다"가 아니라 "운영하면서 개선했다"는 스토리가 강력합니다.

배포 → 모니터링 → 이슈 발견 → 원인 분석 → 개선 → 재배포 → 검증

**예시:**

1. Grafana 대시보드에서 특정 시간대 P99 지연시간 급증 발견

2. Jaeger 분산 추적으로 Feature Store 조회 병목 확인

3. Redis 캐시 히트율 분석 → 캐시 키 전략 개선

4. 결과: Feature Store 조회 지연시간 80% 감소,

캐시 히트율 60%에서 92%로 향상

7. 포트폴리오 프로젝트 아이디어

프로젝트 1: ML 모델 서빙 플랫폼

**기술스택:** FastAPI + Triton Inference Server + Kubernetes + ArgoCD

**구현 범위:**

- FastAPI 기반 모델 서빙 Gateway API

- Triton Inference Server로 실제 모델 서빙

- ONNX 모델 변환 및 최적화 파이프라인

- Dynamic Batching 설정 및 벤치마크

- K8s Deployment + HPA 오토스케일링

- Helm Chart로 패키징

- ArgoCD GitOps 배포

- Prometheus + Grafana 모니터링

- OpenTelemetry 분산 추적

**차별화 포인트:**

- 모델 버전 관리 및 카나리 배포 구현

- A/B 테스트 프레임워크 통합

- 성능 벤치마크 결과 포함 (P50, P95, P99 지연시간, 처리량)

프로젝트 2: 실시간 이상 탐지 시스템

**기술스택:** Kafka + Python + ML 추론 + Redis + PostgreSQL

**구현 범위:**

- Kafka Consumer로 실시간 거래 이벤트 수집

- Feature 실시간 계산 (시간 윈도우 기반 통계)

- Redis를 활용한 온라인 Feature Store

- ML 모델로 이상 거래 판별

- 판별 결과 DB 저장 및 알림 발송

- Grafana 대시보드로 실시간 모니터링

**차별화 포인트:**

- 실시간 스트리밍 처리 경험 증명

- 초당 수천 건 처리 성능 벤치마크

- 모델 재학습 트리거 구현 (Data Drift 감지)

프로젝트 3: AI 챗봇 백엔드 (RAG + LLM 서빙)

**기술스택:** FastAPI + LangChain + 벡터 DB + GPU 서빙

**구현 범위:**

- RAG(Retrieval-Augmented Generation) 아키텍처 설계

- 문서 임베딩 파이프라인 (청킹, 벡터화, 저장)

- 벡터 DB (Milvus, Qdrant, Pinecone 중 선택)

- LLM 서빙 (vLLM 또는 TGI 활용)

- 스트리밍 응답 구현 (SSE)

- 대화 히스토리 관리

- 속도 제한(Rate Limiting) 구현

- K8s GPU 노드 스케줄링

**차별화 포인트:**

- LLM 서빙은 최신 트렌드이며 토스뱅크 AI 챗봇과 직결

- GPU 리소스 관리 경험 증명

- 토큰 사용량 모니터링 및 비용 최적화

실전 퀴즈

배운 내용을 점검해 봅시다.

**정답:** 요청이 도착한 후 최대 5ms(5000마이크로초) 동안 추가 요청을 기다리면서 배치를 구성합니다. 이 시간 내에 더 많은 요청이 도착하면 하나의 배치로 묶어 GPU에서 한 번에 처리합니다.

**핵심 트레이드오프:**

- 값을 높이면: 배치 크기가 커져 GPU 활용률은 높아지지만, 개별 요청의 지연시간이 증가합니다

- 값을 낮추면: 개별 요청의 지연시간은 줄어들지만, 배치 크기가 작아져 GPU 활용률이 낮아집니다

- P99 SLA 요구사항에 맞게 조절해야 합니다

**정답:** HALF_OPEN 상태는 서킷 브레이커가 OPEN(차단) 상태에서 설정된 복구 대기 시간이 지난 후 진입하는 상태입니다.

이 상태에서는 **제한된 수의 요청만 통과**시켜 하류 서비스가 정상으로 복구되었는지 확인합니다.

- 테스트 요청이 성공하면: CLOSED(정상) 상태로 전환하여 모든 트래픽을 다시 통과시킵니다

- 테스트 요청이 실패하면: 다시 OPEN 상태로 돌아가 복구 대기 시간을 리셋합니다

이를 통해 장애가 복구된 서비스에 갑자기 대량 트래픽이 유입되는 "thundering herd" 문제를 방지합니다.

**정답:** 온라인 스토어와 오프라인 스토어는 요구사항이 완전히 다르기 때문입니다.

**오프라인 스토어 (학습용):**

- 대용량 데이터 저장 (수 TB ~ PB)

- 배치 처리로 대량 읽기 가능

- 지연시간은 크게 중요하지 않음 (초~분 단위 허용)

- 보통 BigQuery, S3, Hive 등 사용

**온라인 스토어 (서빙용):**

- 실시간 개별 조회 (key-value 패턴)

- 밀리초 단위의 낮은 지연시간 필수

- 비교적 작은 데이터 (최신 피처 값만)

- 보통 Redis, DynamoDB 등 사용

**가장 중요한 원칙:** Training-Serving Skew(학습-서빙 불일치)를 방지하기 위해, 같은 피처 정의를 양쪽 스토어에서 공유해야 합니다.

**정답:** P99 지연시간이 더 중요합니다.

평균 지연시간은 극단적으로 빠르거나 느린 요청이 서로 상쇄되어 실제 사용자 경험을 왜곡합니다. 예를 들어 평균 50ms라도, 1%의 사용자가 2초 이상 기다릴 수 있습니다.

P99 지연시간은 "99%의 요청이 이 시간 안에 응답된다"는 의미이므로, 대부분의 사용자 경험을 보장합니다.

금융 서비스에서 SLA를 정의할 때도 P99 (또는 P99.9)를 기준으로 하는 것이 일반적입니다. 100명 중 1명이라도 느린 응답을 받으면 그것이 바로 서비스 품질 문제이기 때문입니다.

**추가로 알면 좋은 점:** P99가 높다면 GC(Garbage Collection) 정지, 콜드 스타트, 캐시 미스 등 간헐적 원인을 조사해야 합니다.

**정답:** 새 모델에 예상치 못한 문제가 있을 때 영향 범위를 최소화하기 위해서입니다.

**단계적 증가 전략:**

1. 10%로 시작하여 에러율, 지연시간, 비즈니스 메트릭 관찰

2. 문제가 없으면 25% → 50% → 75% → 100%으로 점진적 증가

3. 각 단계에서 충분한 관찰 시간을 확보 (통계적 유의성 확보)

4. 문제 발생 시 즉시 0%로 롤백

**ML 모델 특유의 고려사항:**

- 모델 정확도는 A/B 테스트 기간 동안 충분한 데이터가 모여야 평가 가능합니다

- 일부 edge case에서만 성능이 떨어지는 모델 문제를 사전에 발견할 수 있습니다

- 금융 도메인에서는 모델 오류가 직접적인 금전적 손실로 이어지므로 더욱 보수적인 접근이 필요합니다

10%는 업계에서 일반적으로 사용하는 초기 비율이며, 서비스 특성에 따라 5% 또는 1%로 더 보수적으로 시작하기도 합니다.

참고 자료

서적

1. **"Designing Data-Intensive Applications"** - Martin Kleppmann: 분산 시스템의 바이블로, 데이터 시스템 설계의 핵심 원칙을 학습할 수 있습니다

2. **"System Design Interview Vol.1 & Vol.2"** - Alex Xu: 시스템 설계 면접 준비의 필수서로, 실전 설계 문제와 풀이를 다룹니다

3. **"Building Machine Learning Pipelines"** - Hannes Hapke: ML 파이프라인의 전체 라이프사이클을 다루는 실무서입니다

4. **"Kubernetes in Action"** - Marko Luksa: K8s 아키텍처부터 실전 운영까지 체계적으로 학습할 수 있습니다

5. **"Designing Machine Learning Systems"** - Chip Huyen: ML 시스템 설계의 핵심 원칙과 패턴을 배울 수 있습니다

온라인 강좌

6. **Stanford CS329S: Machine Learning Systems Design**: ML 시스템 설계에 관한 스탠포드 강의로, ML 서빙 아키텍처를 깊이 학습할 수 있습니다

7. **Google SRE Book (sre.google/books)**: Site Reliability Engineering의 원칙과 사례를 다루며, SLA 관리와 장애 대응에 대한 인사이트를 제공합니다

8. **Kubernetes 공식 문서 (kubernetes.io/docs)**: K8s의 모든 리소스와 개념을 참고할 수 있는 공식 레퍼런스입니다

기술 블로그 및 자료

9. **NVIDIA Triton Inference Server Documentation**: Triton의 모든 기능과 설정을 상세히 다루는 공식 문서입니다

10. **OpenTelemetry 공식 문서 (opentelemetry.io)**: 분산 추적 표준의 개념, SDK, Collector 설정을 학습할 수 있습니다

11. **Feast Documentation (feast.dev)**: Feature Store의 아키텍처와 사용법을 학습하는 공식 가이드입니다

12. **BentoML 공식 문서 (docs.bentoml.com)**: Python 기반 모델 서빙 프레임워크의 튜토리얼과 레퍼런스입니다

13. **토스 기술 블로그 (toss.tech)**: 토스 그룹의 기술 문화와 엔지니어링 사례를 파악하는 데 필수적인 자료입니다

14. **MLOps Community (mlops.community)**: ML 운영에 관한 실무 사례와 최신 트렌드를 공유하는 커뮤니티입니다

15. **The ML Engineer Newsletter**: ML 엔지니어링 분야의 최신 논문, 도구, 사례를 정리한 뉴스레터입니다

실습 플랫폼

16. **Katacoda/Killercoda**: 브라우저에서 바로 K8s를 실습할 수 있는 인터랙티브 환경입니다

17. **k6 Documentation (k6.io)**: 성능 테스트 도구의 사용법과 스크립트 작성 가이드입니다

18. **Grafana Play (play.grafana.org)**: Grafana 대시보드를 직접 체험해볼 수 있는 데모 환경입니다

현재 단락 (1/1187)

토스뱅크 ML Service Team은 은행 서비스 전반에 걸쳐 AI/ML 기술을 프로덕션 레벨로 서빙하는 핵심 팀입니다. 단순히 모델을 만드는 것이 아니라, 수천만 사용자가 실시...

작성 글자: 0원문 글자: 32,372작성 단락: 0/1187