본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 21. 19:38

확장 가능한 RAG를 어떻게 설계했는가 - 2026년을 위한 실무 가이드

요약

트래픽 급증 상황에서 확장 가능한 RAG 시스템을 설계하고 운영하기 위한 실무 가이드를 제공합니다. 단순한 구조를 넘어 분산 시스템으로서의 RAG 파이프라인 구축, 지연 시간 최적화, 그리고 DeepSeek V4를 활용한 비용 효율적인 모델 운영 전략을 다룹니다.

핵심 포인트

  • RAG는 단순한 워크플로우가 아닌 분산 시스템으로 설계해야 함
  • P99 지연 시간 관리를 위해 LLM 단계의 병목 현상 파악이 필수적임
  • DeepSeek V4를 활용하여 컨텍스트 처리 능력과 비용 효율성을 동시에 확보
  • 실제 프로덕션에서는 임베딩 큐 배압 및 토큰 스로틀링 등 변수를 고려해야 함

자, 상황은 이랬습니다: 확장 가능한 RAG를 어떻게 설계했는가 - 2026년을 위한 실무 가이드

저는 아직도 새벽 3시의 그 페이지를 기억합니다. 우리의 검색 증강 생성 (RAG, Retrieval-Augmented Generation) 시스템은 예상치 못한 유럽 시장의 트래픽 급증으로 인해 무너지고 있었습니다. P99 지연 시간 (latency)은 11초를 넘어섰고, 캐시 계층 (cache layer)은 워밍업 (warm-up) 속도보다 더 빠르게 데이터를 방출하고 있었으며, 제 Slack은 "API가 다운되었나요?"라는 메시지들로 가득한 공동묘지 같았습니다. 그날 밤은 그 어떤 백서 (whitepaper)도 가르쳐주지 않은 것을 깨닫게 해주었습니다. RAG 파이프라인은 Jupyter notebook이 아닙니다. 그것은 분산 시스템 (distributed system)이며, 그에 맞춰 설계되어야 합니다.

그 이후로 저는 그 파이프라인을 세 번 재구축했습니다. 현재 운영 중인 세 번째 반복 버전은 DeepSeek V4를 Pinecone과 결합하고 모든 것을 Global API를 통해 라우팅합니다. 우리는 99.9%의 가동 시간 (uptime) 목표를 유지하고 있으며, p99 검색-응답 시간 (retrieval-to-answer time)은 4.2초 미만으로 안정적으로 유지됩니다. 덕분에 재무 담당자도 월간 인보이스가 도착할 때 더 이상 움찔하지 않습니다. 만약 당신이 2026년에 이와 유사한 것을 구축하고 있다면, 12개월 전에 누군가 저에게 건네주었기를 바랐던 현장 가이드를 여기에 공개합니다.

아무도 경고해주지 않는 프로덕션의 현실

대부분의 RAG 블로그 포스트는 임베딩 (embed), 검색 (retrieve), 생성 (generate)으로 끝나는 깔끔한 두 개의 박스 다이어그램을 설명합니다. 그것은 마케팅 브로슈어일 뿐입니다. 실제 프로덕션 (production) 환경에서는 임베딩 큐 배압 (embedding queue backpressure), 재수집 (re-ingestion) 중 발생하는 벡터 인덱스 변동 (vector index churn), 업스트림 LLM 제공업체의 토큰 버킷 스로틀링 (token bucket throttling), 그리고 모든 모델이 긴 컨텍스트 (long context)를 우아하게 처리하지는 못한다는 냉혹한 진실을 다루게 됩니다. 지연 시간 (latency)은 단순히 "첫 번째 토큰까지의 시간 (time to first token)"이 아닙니다. 사용자의 HTTP 요청이 당신의 에지 (edge)에 도착한 시점부터 답변의 마지막 토큰이 렌더링될 때까지의 시간입니다. 모든 단계는 꼬리 지연 (tail)을 추가하며, 이 꼬리들은 복합적으로 작용합니다.

우리의 파이프라인을 제대로 계측(instrumenting)하기 시작했을 때, 저는 p99 지연 시간(latency)의 30%가 Pinecone이 아니라 실제로는 LLM 단계에서 발생한다는 사실을 알고 충격을 받았습니다. 플래그십 모델에서 전 세계적으로 라우팅할 수 있는 더 가벼운 모델로 교체한 것이 올해 가장 큰 단일 성과를 가져다주었습니다. 바로 그 지점에서 DeepSeek V4가 등장했고, 가격 책정이 갑자기 추상적인 스프레드시트상의 연습이 아닌 현실이 되었습니다.

왜 DeepSeek V4가 나에게 맞았는가

저는 세 가지를 동시에 수행할 수 있는 모델이 필요했습니다: 128K 컨텍스트 윈도우 (context windows)를 막힘없이 처리하고, 첫 번째 토큰 지연 시간 (first-token latency)을 낮게 유지할 수 있을 만큼 충분히 빠르게 토큰을 스트리밍하며, 트래픽이 두 배로 늘어나도 저를 파산시키지 않는 모델 말입니다. DeepSeek V4 Flash는 처음 두 가지를 충족했고, 세 번째는 단위 경제성 (unit economics)에서 해결되었습니다. Global API를 통해 DeepSeek V4 Flash는 입력 토큰 100만 개당 $0.27, 출력 토큰 100만 개당 $1.10에 실행됩니다. 입력 $2.50, 출력 $10.00인 GPT-4o와 비교하면, 계산은 더 이상 논쟁의 대상이 아닙니다.

누군가 "하지만 더 저렴한 모델이 충분히 성능이 좋을까요?"라고 물을 때마다 매번 다시 계산하지 않도록 모니터에 작은 표를 붙여두었습니다:

모델입력 $/M출력 $/M컨텍스트 (Context)
DeepSeek V4 Flash0.271.10128K
...

이 정확한 수치들 덕분에 저는 한 달에 수백만 개의 쿼리에 답변하는 RAG 워크로드를 실행하면서도 분기 예산을 훨씬 밑도는 비용을 유지할 수 있습니다. 제가 수행한 초기 비용 분석에 따르면, 이전의 GPT-4o 기반 스택 대비 40-65%의 비용 절감이 나타났으며, 내부 평가 세트 (eval set)에서 측정한 평균 벤치마크 점수 84.6%는 품질이 희생되지 않았음을 확인시켜 주었습니다. Global API를 통해 184개의 모델을 사용할 수 있고 가격이 토큰 100만 개당 $0.01에서 $3.50 사이로 형성되어 있어, 6개의 서로 다른 SDK를 번갈아 사용할 필요 없이 까다로운 케이스(예: 구조화된 추출을 위한 Qwen3-32B)를 위한 전문 모델을 선택할 수도 있습니다.

실제 연결 구조는 어떻게 생겼는가

다음은 제가 모든 서비스에 걸쳐 표준화한 핵심 클라이언트입니다. Global API의 OpenAI 호환 엔드포인트 덕분에, 저희 팀은 새로운 모델을 테스트하고 싶을 때마다 매번 새로운 SDK를 배울 필요가 없습니다. 이는 사소해 보일 수 있지만, 분기당 수 주간의 온보딩(onboarding) 시간을 절약해 줍니다.

import openai
import os
import time
...

저에게 stream=True 플래그는 타협할 수 없는 요소입니다. 사용자는 전체 지연 시간(latency)이 동일하더라도 스트리밍 응답을 더 빠르다고 인식하며, p99 첫 번째 토큰 생성 시간(time-to-first-token, TTFT)은 전체 응답 시간보다 더 의미 있는 SLA(Service Level Agreement) 지표가 됩니다. 저는 Datadog에서 TTFT를 별도로 추적하고 있으며, 저희와 가장 가까운 Global API 엣지(edge)에서 제공하는 DeepSeek V4 Flash의 경우 약 380ms를 유지하고 있습니다. 저희가 측정하는 처리량(throughput)은 95번째 백분위수(95th percentile) 기준으로 초당 약 320 토큰이며, 이는 UI를 부드럽게 유지하기에 충분한 수치입니다.

p99 부하에서의 비용 모델링 (Cost Modeling)

제가 고생하며 배운 비결은 평균 부하(average load)를 기준으로 예산을 잡는 것이 아니라, CDN이 선사할 수 있는 최악의 날을 기준으로 예산을 잡아야 한다는 것입니다. 저는 트래픽이 기본값의 3배가 되고, LLM 제공업체의 속도 제한(rate limit)이 중간에 걸리는 시나리오를 모델링합니다. 캐시 계층(cache layer)이 첫 번째 파도를 흡수하고, 오토스케일러(auto-scaler)가 추가적인 검색 워커(retrieval workers)를 가동하며, 초과분은 더 저렴한 폴백(fallback) 모델로 라우팅합니다.

여기에서 GA-Economy가 역할을 합니다. DeepSeek V4 Pro의 전체 컨텍스트 윈도우(context window)가 필요하지 않은 간단한 조회(lookup)의 경우, Global API의 이코노미 티어(economy-tier) 모델 중 하나로 요청을 보내 약 50% 적은 비용을 지불합니다. 마이크로서비스(microservices) 군단 전체에 걸쳐 이 50%는 복리로 쌓입니다. 또 다른 레버(lever)는 캐싱입니다. 프롬프트 캐시(prompt-cache) 수준에서 40%의 히트율(hit rate)을 달성함으로써 작년에 엔지니어 한 명의 연봉에 해당하는 비용을 절감했으며, 이를 위해 인프라 코드를 단 한 줄도 새로 작성할 필요가 없었습니다.

멀티 리전 아키텍처 (Multi-Region Architecture)

우리는 us-east, eu-west, ap-southeast의 세 개 리전에 걸쳐 액티브-액티브 (active-active) 방식으로 운영합니다. Pinecone은 특정 인덱스에 대해 의도적으로 단일 리전에 유지하는 유일한 구성 요소이지만, 최대 90초의 지연을 가진 비동기 파이프라인 (async pipeline)을 통해 리전 간 네임스페이스 토폴로지 (namespace topology)를 복제합니다. 읽기 작업은 가장 가까운 리전에서 처리됩니다. LLM 호출은 자체적인 멀티 리전 (multi-region) 기반을 갖추고 있어 어디서나 동일한 베이스 URL을 유지할 수 있게 해주는 Global API를 통해 이루어집니다:

저 단일 URL은 보기보다 훨씬 많은 일을 수행합니다. 사용자 근처에서 TLS 종료 (TLS termination)를 처리하고, 가장 상태가 좋은 업스트림 모델 제공업체로 라우팅하며, 테넌트별 속도 제한 (per-tenant rate limits)을 적용하고, 제가 호출을 받았을 때(paged) 확인할 수 있는 단일 지점을 제공합니다. 다섯 개의 서로 다른 벤더 SDK를 위한 상태 확인 (health-check) 루프를 작성할 필요가 없습니다. 저는 단 하나만 작성하면 됩니다.

다음은 서킷 브레이커 (circuit breaker) 패턴과 폴백 (fallback) 모델을 포함한 제 운영 환경의 검색 서비스 (retrieval service)에서 가져온 보다 현실적인 코드 스니펫입니다:

import openai
import os
import logging
...

데코레이터 (decorator)에 주목하세요. 특정 시간 범위 내에서 기본 모델이 5번 실패하면 서킷이 열리고(circuit opens) 더 이상 모델을 몰아붙이지 않습니다. 이 작은 로직 조각은 제가 셀 수 없을 정도로 많은 횟수 동안 연쇄 장애 (cascading failures)로부터 우리를 구해냈습니다. 이는 튜토리얼에는 등장하지 않지만, 99.9%의 가동 시간 (uptime)을 달성하는 데 있어 절대적으로 중요한 요소입니다.

SLA, 폴백(Fallback), 그리고 호출을 받아본 후에야 배우게 되는 것들

SLA에 대해 솔직하게 말씀드리겠습니다. Global API는 경쟁력 있는 가동 시간을 광고하지만, 고객에 대한 저의 내부 SLA는 제가 지켜야 할 몫입니다. 이는 모델 제공업체, 벡터 DB (vector DB), 임베딩 서비스 (embedding service), 그리고 캐시 (cache) 등 실패할 수 있는 모든 것에 대해 폴백 경로가 필요함을 의미합니다. 특히 LLM의 경우, 품질을 유지하기 위한 폴백으로는 DeepSeek V4 Pro 엔드포인트를 상시 대기(warm) 상태로 유지하고, 비용을 절감하기 위한 폴백으로는 GA-Economy를 사용합니다. 또한 모든 LLM 경로가 다운될 경우, 더 짧은 스니펫 형태의 답변만 반환함으로써 우아하게 성능을 저하시킵니다 (degrade gracefully). Pinecone만으로도 여전히 유용하며, 제 사용자들은 504 에러를 받는 것보다 차라리 좋은 발췌문이라도 받는 것을 선호하기 때문입니다.

관측성 (Observability)을 위해, 저는 각 단계별 지연 시간 (latency)을 구조화된 로그 (structured logs) 및 Prometheus 히스토그램 (histogram)으로 방출합니다. 모든 요청에는 에지 (edge)에서 LLM을 거쳐 다시 돌아올 때까지 추적되는 상관 관계 ID (correlation ID)가 부여됩니다. p99가 급증할 때, 저는 원인이 검색 (retrieval), 임베딩 (embedding), 또는 생성 (generation) 중 어디에 있는지 즉시 파악할 수 있습니다. 제 경험상, 원인은 여러분이 생각하는 곳에 있는 경우가 거의 없습니다.

파이프라인의 엔드 투 엔드 (End-to-End) 벤치마킹

저는 매주 500개의 실제 사용자 쿼리를 프로덕션 파이프라인을 통해 재현하고, 사람이 큐레이션한 정답 (ground truth)과 비교하여 답변의 점수를 매기는 평가 (eval) 작업을 실행합니다. 평균 점수는 약 84.6%를 유지하며, 중요한 점은 주간 점수 분산 (variance)이 작다는 것입니다. 그 안정성이 핵심입니다. 벤치마크에서는 2% 더 뛰어나지만 주간 변동성이 심한 모델은, 일관되게 좋은 성능을 보이는 모델보다 프로덕션 환경에서 더 나쁜 선택입니다.

지연 시간 측면에서, 평균 엔드 투 엔드 (end-to-end) 시간은 1.2초입니다. P95는 약 2.8초이며, P99는 4.2초로, 이 수치를 이해관계자들에게 보고합니다. P99를 초과하는 모든 수치는 이상치 (outliers)로 간주하고 개별적으로 조사합니다. 왜냐하면 p99.9를 쫓는 것은 대개 모델과 아무런 관련이 없는 천 번 중 한 번 발생하는 이벤트를 위해 과도하게 리소스를 할당 (over-provisioning)하는 것을 의미하기 때문입니다.

슬라이드에 담기지 않는 운영상의 교훈

잊어버리기 전에 기록해두고 싶은 몇 가지 배운 점들이 있습니다.

첫째, 전체 RAG 파이프라인을 단일 모델 의존성 (dependency) 뒤에 두지 마세요. 해당 모델에 지역적 장애 (regional outage)가 발생하는 날이 반드시 올 것이며, 여러분은 부사장 (VP)에게 왜 챗봇이 작동하지 않는지 설명해야 할 것입니다. 보조 모델 (secondary model)과 우아한 성능 저하 (graceful degradation) 경로를 구축하는 데는 아마 하루 정도면 충분하며, 이는 여러분의 분기별 고통을 줄여줄 것입니다.

둘째, 임베딩 모델 (embedding model)도 동일하게 취급하세요. 임베딩 드리프트 (embedding drift)는 실제로 발생하는 현상이며, 다른 모델로 코퍼스 (corpus)를 다시 임베딩하는 것은 단순한 설정 변경이 아니라 하나의 프로젝트입니다. 저희는 실제 전환을 하기 전에 새로운 임베딩을 섀도 모드 (shadow mode)로 실행하는 병렬 인덱스 (parallel index)를 운영하고 있습니다.

셋째, 프롬프트 캐시 (prompt cache)는 도움이 되지만 구원자는 아닙니다. 반복적인 내부 트래픽의 경우 40%의 히트율 (hit rate)이 현실적이지만, 외부 사용자에게 서비스를 제공한다면 15-25%를 예상하고 그에 따라 예산을 책정하십시오.

넷째, 체감 속도를 위해 튜닝할 때는 전체 지연 시간 (total latency)이 아니라 첫 토큰 시간 (TTFT, Time To First Token)을 측정하십시오. 첫 단어가 0.5초 이내에 나타난다면 사용자들은 느린 답변도 용서합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0