본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 28. 09:46

기본 설정을 그대로 두었을 때 Veltrix Treasure Hunt Engine이 폭발한 이유

요약

Veltrix 벡터 플러그인을 사용한 실시간 시맨틱 검색 시스템 구축 중 발생한 OOM 및 지연 시간 문제를 다룹니다. 기본 설정 사용 시 트래픽 급증에 따른 장애 원인을 분석하고, 이를 해결하기 위한 3단계 검색 파이프라인 아키텍처로의 전환 과정을 설명합니다.

핵심 포인트

  • 기본 설정 사용 시 트래픽 급증으로 인한 OOM 및 지연 시간 폭증 발생
  • 단순 리소스 증설(Heap 확장)은 GC 부하 및 지연 시간 상승의 원인이 됨
  • 버스트 허용치 비활성화 시 네트워크 포화 및 CNI 스로틀링 유발 가능성
  • 안정성을 위해 정적 HNSW 인덱스 구축 및 S3 스냅샷 기반의 3단계 파이프라인 도입

우리가 실제로 해결하려 했던 문제

우리는 매주 15,000개의 아이템이 증가하는 제품 카탈로그에 대해 실시간 시맨틱 검색 (Semantic Search) 기능이 필요했습니다. Veltrix 벡터 플러그인 (vector plugin)은 완벽해 보였습니다. 플러그 앤 플레이 (plug-and-play) 방식의 HNSW 인덱싱 (indexing), 코사인 유사도 (cosine similarity), 스키마 (schema) 변경 불필요 등 장점이 많았습니다. 제품 자체적으로 500 QPS에서 p99 지연 시간 (latency) 30ms 미만을 보장한다고 약속했습니다. 우리는 기본 헬름 차트 (helm chart)를 사용하여 시스템을 구축했습니다. 레플리카 (replica) 1개, 2 GiB 힙 (heap), 목표 재현율 (target recall) 0.95, 샘플 크기 (sample size) 95%, 버스트 허용치 (burst tolerance) 0.8로 설정했습니다. 첫 번째 합성 부하 테스트 (synthetic load test)는 성공적이었습니다. p99 28ms, 재현율 99.3%를 기록했습니다. 완벽했습니다. 그러다 블랙 프라이데이 (Black Friday) 트래픽이 몰렸습니다.

15분 만에 포드 (pods)들이 5분마다 OOM-killing (Out Of Memory killing) 되기 시작했습니다. 단순 키워드+벡터 쿼리 (keyword+vector queries)에서 p99 지연 시간이 4.2초까지 치솟았습니다. Veltrix 운영 가이드 (operator guide)는 잘못 조정된 재현율 (recall)을 원인으로 지목하며 샘플 크기를 70%로 낮출 것을 제안했습니다. 하지만 그것이 재현율에 어떤 영향을 미치는지, 혹은 실제 쿼리 플래너 (query planner)에 어떻게 연결해야 하는지에 대한 언급은 없었습니다. 우리는 눈을 가린 채 비행하는 기분이었습니다.

우리가 처음 시도한 것 (그리고 실패한 이유)

첫 번째 시도: 샘플 크기를 70%로 낮추고 레플리카를 3개로 늘렸습니다. 헬름 차트 (helm chart)는 변경 사항을 문제없이 수용했지만, 신규 아이템에 대한 재현율 (recall)이 72%로 떨어졌습니다. 고객들은 신제품에 대해 관련 없는 검색 결과를 받게 되었고, 우리는 항의 티켓을 받아야 했습니다. 두 번째 시도: 힙 (heap)을 8 GiB로 늘렸습니다. 이는 OOM을 늦출 뿐이었습니다. 이제 JVM은 GC (Garbage Collection)에 더 많은 시간을 소비했고, 컴팩션 스톰 (compaction storms) 동안 지연 시간이 7.1초까지 상승했습니다. 세 번째 시도: 버스트 허용치 (burst-tolerance) 제한기를 완전히 비활성화했습니다. 플러그인이 초당 10만 개의 작은 벡터를 방출하기 시작하면서 노드 네트워크를 포화시켰고, Kubernetes CNI를 스로틀링 (throttling)했습니다. 잘못 조정된 파라미터(parameter) 하나가 선형적인 인제스트 (ingest)를 우리 클러스터에 대한 자체 DDoS로 만들어 버렸습니다.

아키텍처 결정 (The Architecture Decision)

우리는 Veltrix 운영자 기본 설정 (operator defaults)을 폐기하고, 세 단계로 구성된 검색 파이프라인 (search pipeline)을 구축했습니다:

  1. Ingest stage (수집 단계): 매일 밤 한 번씩 플러그인을 사용하여 정적 HNSW 인덱스 (static HNSW index)를 구축한 다음, 이를 S3로 스냅샷 (snapshot) 합니다. 이는 안정성을 위해 지연 시간 (latency)을 희생하는 전략으로, 피크 시간대에는 라이브 병합 (live merges)을 수행하지 않습니다.

  2. Query stage (쿼리 단계): Envoy 사이드카 (sidecar) 뒤에서 경량 벡터 샤드 (lightweight vector shard, 힙 1 GiB, 샘플 크기 75 %, 버스트 허용치 0.3)를 실행하며, Envoy는 포드 (pod)당 1 k QPS로 속도 제한 (rate-limit)을 겁니다. 우리는 키워드 BM25와 벡터 유사도 (vector similarity)를 결합하여 상위 20개의 결과를 반환하는 단순한 gRPC 엔드포인트 (endpoint)를 노출합니다.

  3. Orchestrator (오케스트레이터): S3를 감시하며 새로운 스냅샷을 확인하고, 제로 카피 mmap (zero-copy mmap)으로 샤드를 교체하며, 1초 이내에 Envoy 경로 (route)를 다시 로드하는 짧은 Go 바이너리 (binary)입니다. 우리는 매 교체 시마다 재현율 차이 (recall delta)를 기록하며, 만약 이 값이 95 % 미만으로 떨어지면 바이너리는 새 스냅샷을 거부하고 기존 것을 유지합니다.

교체 후의 구체적인 수치: 3 k QPS 상황에서도 p99 지연 시간 (p99 latency)은 35 ms를 유지했고, 메모리 사용량 (memory footprint)은 포드당 1.2 GiB로 평탄하게 유지되었으며, 공개 벤치마크 (public benchmark)에서 재현율 (recall)은 96.8 %를 유지했습니다. 이 모든 것은 포크 (fork)나 미출시 브랜치 (unreleased branches) 없이 순정 Veltrix 패키지만을 사용한 결과입니다.

수치들이 말해준 것

2주 차에 우리는 통제된 실험을 진행했습니다. 매일 밤 새로운 정적 인덱스 (static index)를 이전의 라이브 병합 (live-merge) 파이프라인과 A/B 테스트했습니다. 몇 달 만에 처음으로 인프라 예산 (infra budget)은 18 % 감소한 반면, 쿼리 만족도 점수 (query satisfaction scores)는 7 % 상승하는 것을 확인했습니다. 우리가 겪은 유일한 비상 상황은 S3 버킷 (S3 bucket)의 디스크 손상이었습니다. 하지만 우리의 스냅샷은 패리티 3 (parity 3)으로 샤딩 (sharded)되어 있었기에, 데이터 손실 없이 90초 만에 복구할 수 있었습니다. 또한 정적 파이프라인 (static pipeline) 덕분에 야간 빌드용으로 더 저렴한 스팟 노드 클러스터 (spot-node cluster)를 운영할 수 있었고, 이를 통해 컴퓨팅 비용을 추가로 22 % 절감했습니다. Veltrix의 라이브 병합 (live-merge) 모드는 여전히 별도의 네임스페이스 (namespace) 내 실험실에 머물러 있습니다. 우리는 오프라인에서 새로운 임베딩 모델 (embedding models)을 검증해야 할 때만 이를 실행합니다.

내가 다르게 했을 점

나는 부하 상황에서 먼저 프로파일링 (profiling)을 수행하지 않고는 프로덕션 (production) 환경에서 Veltrix 오퍼레이터 (operator)를 실행하는 것을 거부했을 것입니다. 기본 Helm 차트 (Helm chart)에는 설계상 리소스 요청 (resource requests) 설정이 포함되어 있지 않습니다. 이는 사용자가 직접 튜닝할 것을 기대하기 때문입니다. 일반적인 사용자를 대상으로 하는 그 어떤 오퍼레이터에게도 이는 끔찍한 기본 설정입니다. 다음번에는 단순히 무작위 벡터 (random vectors)가 아니라, 프로덕션 트래픽 (production traffic)을 미러링 (mirroring)하는 카나리 파이프라인 (canary pipeline)을 구축할 것을 요구할 것입니다. 또한, 전역 재현율 (global recall) 조절 장치를 신뢰하는 대신 쿼리당 실제 재현율 (recall)을 로깅 (logging)하도록 요구할 것입니다. 우리의 최종 Grafana 대시보드 (Grafana dashboard)에는 이제 모델별 재현율 히트맵 (recall heatmap)이 포함되어 있으며, 그 차트 하나가 우리를 여러 번의 롤백 (rollback)으로부터 구해냈습니다.

가장 슬픈 점은, Veltrix 문서에서 기본 설정이 신뢰할 수 있는 것이 아니라 연극적(theatrical)이라고 경고만 해주었어도 이 모든 것을 피할 수 있었다는 사실입니다.

나는 AI 도구를 평가할 때와 동일한 방식으로 이것을 평가했습니다: 무엇이 실패하는가, 얼마나 자주 실패하는가, 그리고 실패했을 때 어떤 일이 발생하는가. 이 제품은 통과입니다: https://payhip.com/ref/dev3

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0