fos-blog/study
01 / 홈02 / 카테고리03 / 시리즈
01 / 홈02 / 카테고리03 / 시리즈

카테고리

  • AI 페이지로 이동
    • RAG 페이지로 이동
    • agent 페이지로 이동
    • claude-code 페이지로 이동
    • harness 페이지로 이동
    • llm 페이지로 이동
    • ops 페이지로 이동
    • practice 페이지로 이동
  • algorithm 페이지로 이동
    • Alias Method: 가중치 랜덤 선택을 전처리 O(n), 추출 O(1)로 바꾸기
    • Welford's Online Algorithm: 값을 저장하지 않고 평균과 분산 계산하기
  • architecture 페이지로 이동
    • distributed-systems 페이지로 이동
    • domain 페이지로 이동
    • evolution 페이지로 이동
    • patterns 페이지로 이동
  • database 페이지로 이동
    • milvus 페이지로 이동
    • mysql 페이지로 이동
    • opensearch 페이지로 이동
    • postgresql 페이지로 이동
    • qdrant 페이지로 이동
    • redis 페이지로 이동
    • vespa 페이지로 이동
    • DB Connection Pool Saturation과 Thread Pool 격리
    • 커넥션 풀 크기는 얼마나 조정해야 할까?
    • gaps and islands: SQL 창 함수로 이어진 구간 찾기
    • MyBatis 기본기 — XML Mapper, resultMap, 동적 SQL, 운영 패턴 정리
    • MyBatis와 JPA/Hibernate 트레이드오프 — 레거시 백엔드를 다루는 시니어 관점
    • 한국어 형태소 분석기 Nori vs Lindera — OpenSearch에서 Milvus로 갈 때 어휘 검색은 유지되나
    • 정규화와 역정규화: 무결성과 조회 비용 사이의 선택
    • 벡터 DB 5종, 아키텍처는 어떻게 다른가
    • 벡터 DB 5종을 실제로 벤치마크했다 — 같은 recall에서 QPS는 얼마나 갈리나
    • 벡터 DB 어떻게 고를까 — OpenSearch · Milvus · Qdrant · Vespa · pgvector 비교
    • 벡터 DB를 실제로 도입한 사례 — 빅테크 프로덕션
  • devops 페이지로 이동
    • docker 페이지로 이동
    • k8s 페이지로 이동
    • Envoy Proxy
    • Graceful Shutdown
    • 종료 신호는 어디서 멈추는가
  • http 페이지로 이동
    • HTTP Connection Pool
    • HTTPS와 TLS: 핸드셰이크, 인증서, 종료 지점
  • java 페이지로 이동
    • concurrency 페이지로 이동
    • jdbc 페이지로 이동
    • spring 페이지로 이동
    • spring-batch 페이지로 이동
    • testing 페이지로 이동
    • Alpine 이미지의 Java 에서 링크 바꿔치기(TOCTOU)를 막지 못하는 이유
    • Java 동시성 락 정리 — 커머스 메뉴/프로모션 정책 캐시 갱신 관점
    • JVM 튜닝 실전: 메모리 구조부터 Virtual Threads, GC 튜닝, 프로파일링까지
    • 로그에 traceId 남기기 — MDC 부터 OpenTelemetry 까지
    • Java StampedLock — 읽기 폭주에도 쓰기가 밀리지 않는 락
    • Virtual Thread와 Project Loom
  • javascript 페이지로 이동
    • typescript 페이지로 이동
    • AbortController
    • Async Iterator와 제너레이터
    • CommonJS와 ECMAScript Modules
    • 제너레이터(Generator)
    • Http Client
    • Node 백엔드 운영 패턴 — Streams 백프레셔, pipe/pipeline, 멱등성 vs 분산 락
    • Node.js
    • `setImmediate()`
  • kafka 페이지로 이동
    • Kafka 클러스터 아키텍처: Broker, KRaft Controller와 복제
    • Kafka 기본 개념: Topic, Partition, Offset과 Segment
    • Kafka 실전 설계: 파티션 전략, 컨슈머 그룹, 전달 보장, 재시도, 순서 보장 트레이드오프
    • Kafka 파티션·리밸런스·컨슈머 지연 운영
    • Kafka를 로그로 이해하기: 복제, 재처리, 상태와 데이터 통합
    • Spring Kafka 컨슈머 오프셋 커밋과 트랜잭션 정렬: AckMode, manual ack, 멱등 처리
  • linux 페이지로 이동
    • fsync — 리눅스 파일 동기화 시스템 콜
    • SSH forced command 로 배포 키가 실행할 수 있는 명령 제한하기
  • mlops 페이지로 이동
    • llm-serving 페이지로 이동
    • model-router 페이지로 이동
    • Python CUDA 버전 생태계 — nvidia-smi, nvcc, pip, conda가 다 다른 버전을 말하는 이유
    • GPU 컨테이너의 CUDA 버전 호환성 — nvidia-smi부터 이미지 다이어트까지
    • Kubernetes GPU 노드에서 /run tmpfs가 꽉 차서 Pod가 안 뜰 때
    • GPU·CUDA·MPS 기초 — 자바 백엔드 개발자가 처음 만나는 그림
    • Multi-process GPU 워크로드 — 자바 ThreadPool 사용자가 만나는 모델 차이
    • ML 서비스 성능 분석 워크플로 — 자바 백엔드 트러블슈팅과 다른 점
    • 한 GPU 를 여러 프로세스가 나눠 쓰기 — Time-Slicing 과 MPS
  • network 페이지로 이동
    • Connection reset by peer는 누가 보낸 걸까 — 리버스 프록시 홉마다 TCP 연결은 따로 논다
    • L2(스위치)와 L3(라우터)의 역할 차이
    • L4와 VIP(Virtual IP Address)
    • IP Subnet
  • observability 페이지로 이동
    • Observability 입문: 시니어 백엔드가 장애를 탐지하고 대응하는 방식
    • K8s 위 Spring Boot 앱의 메트릭 수집
  • python 페이지로 이동
    • Python async/await — CompletableFuture·Reactor 와 다른 점, 그리고 blocking I/O 함정
    • Python 의존성 관리 — Java Maven/Gradle 사용자가 만나는 첫 충격
    • FastAPI 기초 — Spring Boot 사용자가 빠르게 익히는 법
    • Java 개발자를 위한 Python 심화 — OOP·데코레이터·컨텍스트 매니저
    • PyTorch 기초 — 텐서, 디바이스, 그리고 모델 로딩이 무거운 이유
    • Java 개발자를 위한 Python 문법 핵심
    • ThreadLocal 에서 contextvars 로 — Python 의 요청 컨텍스트 전파
    • OCR 동작 원리 — Layout · Text · Post-process 3단계
    • Python 서버의 RSS가 줄지 않는 이유: CPython, gc.collect(), malloc_trim
  • rabbitmq 페이지로 이동
    • RabbitMQ Basics — 실전 백엔드 관점에서 정리하는 메시지 브로커 기본기
    • RabbitMQ vs Kafka — 백엔드 메시징 선택 기준과 실전 운영 관점
  • resume 페이지로 이동
    • 경험 및 경력기술서
    • 김병태 경력기술서
    • 김병태 포트폴리오
  • task 페이지로 이동
    • ai-service-team 페이지로 이동
    • nsc-slot 페이지로 이동
    • personal-projects 페이지로 이동
    • sb-dev-team 페이지로 이동
    • the-future-company 페이지로 이동
  • thinking 페이지로 이동
    • 자기주도 학습: 질문에서 시작해 글로 검증하기
    • 좋은 일을 넘어 중요한 일을 하는 법
FOS-BLOG · FOOTERall systems normal·v0.1 · 2026.04.27·seoul, kr
Ffos-blog/study

개발 학습 기록을 정리하는 블로그입니다. 공부하면서 기록하고, 기록하면서 다시 배웁니다.

visitors
01site
  • Home↗
  • Posts↗
  • Categories↗
  • Glossary↗
  • About↗
02policy
  • 소개/about
  • 개인정보처리방침/privacy
  • 연락처/contact
03categories
  • AI↗
  • Algorithm↗
  • DB↗
  • DevOps↗
  • Java/Spring↗
  • JS/TS↗
  • React↗
  • Next.js↗
  • System↗
04connect
  • GitHub@jon890↗
  • Source repositoryjon890/fos-study↗
  • RSS feed/rss.xml↗
  • Newsletter매주 1 회 · 한 편의 글→
© 2026 FOS Study. All posts MIT-licensed.
built with·Next.js·Tailwind v4·Geist·Pretendard·oklch
fos-blog/database/Milvus 3.0이 바꾸는 벡터 데이터 관…
dbai

Milvus 3.0이 바꾸는 벡터 데이터 관리 방식

Milvus 3.0 이 2026년 5월 9일에 3.0-beta 로 공개됐다. 아직 정식 출시(GA)가 아니라 베타다. 2.6.x가 프로덕션 버전이고, 3.0은 미리 보는 단계다. 그래서 이 글은 "지금 올려라"가 아니라 3.0 이 어떤 방향으로 가려 하는지, 그게 어떤 가치인지를 정리한 스터디 노트다. 한 문장으로 줄이면 이렇다. 2.x 가 "벡터 검색 엔...

2026.06.22·5 min read·81 views

Milvus 3.0 이 2026년 5월 9일에 3.0-beta 로 공개됐다. 아직 정식 출시(GA)가 아니라 베타다. 2.6.x가 프로덕션 버전이고, 3.0은 미리 보는 단계다. 그래서 이 글은 "지금 올려라"가 아니라 3.0 이 어떤 방향으로 가려 하는지, 그게 어떤 가치인지를 정리한 스터디 노트다.

한 문장으로 줄이면 이렇다. 2.x 가 "벡터 검색 엔진"을 다듬는 흐름이었다면, 3.0 은 운영 컴포넌트를 더 줄이고, 데이터 레이크와 한 몸이 되려는 흐름이다.

이 글은 Milvus 아키텍처와 동작에서 정리한 2.6 구조를 전제로 한다. storage-compute 분리, segment(growing/sealed), WAL 개념이 아직 낯설면 그 글을 먼저 읽는 게 좋다.

세 갈래의 변화

3.0 의 변경점은 많지만, 묶어 보면 세 갈래다.

  • 운영 단순화: Streaming Node가 기본이 되고, 별도 컴포넌트(indexNode)가 사라지고, 메시지 큐를 자체 WAL로 대체한다.
  • 데이터 레이크 통합: 데이터를 복사해 넣지 않고, 원본이 있는 자리(S3 등)를 그대로 참조해 검색한다.
  • 스키마·검색 표현력: NULL 벡터, 온라인 필드 추가, 서버 측 집계·정렬처럼 관계형 DB에서는 제공하지만 벡터 DB에는 없던 기능을 채운다.

하나씩 본다.

운영 컴포넌트 감소

2.x 를 처음 보면 컴포넌트 수에 질린다. 코디네이터 여러 종류에 워커 노드, 거기에 Kafka/Pulsar 같은 외부 메시지 큐까지 얹혀 있었다. 3.0 은 이 구조를 정리한다.

항목2.5 이전3.0
Streaming Node없음 (또는 2.5 실험적·기본 비활성)기본 활성화
indexNode별도 컴포넌트제거 (역할 흡수)
WAL 메시지 큐Kafka / Pulsar 외부 의존Woodpecker 권장 (zero-disk)

Streaming Node 는 실시간으로 들어오는 데이터를 WAL 에 쓰고 아직 영속화되지 않은 최신 데이터의 검색을 맡는 컴포넌트다. 2.5 에서 실험적으로 들어왔다가 3.0 에서 기본값이 됐다. 스트림 처리(Streaming Node)와 배치 처리(Query Node, Data Node)를 분리해 둔 덕에 실시간 입력과 대량 검색이 서로 간섭하지 않는다.

Woodpecker 는 Kafka/Pulsar 를 대체하는 Milvus 자체 WAL 이다. 별도 큐 서버나 전용 디스크 없이 오브젝트 스토리지에 직접 쓰는 zero-disk 방식이라, 운영자가 따로 관리할 인프라가 줄어든다. 2.6 에서 도입돼 3.0 에서 권장 방식이 됐다. 다만 아키텍처 글에서도 적었듯 상업적 사용 라이선스 이슈가 거론된 적이 있어, 환경에 따라 Kafka 를 그대로 쓰는 선택지도 남겨 둔다.

이게 왜 가치인가. 전용 벡터 DB 를 꺼리는 가장 큰 이유가 "운영할 컴포넌트가 너무 많다"였는데, 3.0 은 정확히 그 부담을 깎는다.

데이터를 복사하지 않는 데이터 레이크 통합

3.0 에서 가장 성격이 다른 변화가 External Collection 이다. 지금까지 벡터 DB 를 쓰려면 원본 데이터를 임베딩해서 DB 안으로 복사해 넣어야 했다. External Collection은 그 복사를 없앤다. 데이터는 원래 있던 자리(레이크의 파일)에 두고, Milvus는 스키마·인덱스·쿼리 실행만 관리한다.

여기에 Storage V3(S3 호환 오브젝트 스토리지 위의 manifest 기반 컬럼 저장 엔진)와 Snapshot(특정 시점의 읽기 전용 뷰)이 더해진다. Spark 가 Milvus 컬렉션을 Snapshot 으로 직접 읽을 수도 있다.

직설적으로 말하면, Milvus 가 별도 섬으로 떨어진 검색 엔진이 아니라 레이크하우스의 한 부품이 되려는 방향이다. 이미 데이터 레이크(S3와 Spark 등)를 운영하는 조직이라면, 데이터를 이중으로 적재하지 않아도 되는 게 실질적인 이득이다.

관계형 DB에 가까워진 스키마와 검색 표현력

벡터 DB 를 쓰다 보면 "이런 기본적인 것도 안 되나" 싶은 순간이 온다. 3.0 은 그 빈칸들을 메운다.

  • Nullable 벡터 필드: 여섯 가지 벡터 타입 모두 NULL을 허용하고, 검색은 NULL 벡터를 자동으로 건너뛴다. 기존 컬렉션에 벡터 필드를 재빌드 없이 온라인으로 추가할 수도 있다.
  • Entity 단위 TTL: 스키마에 TIMESTAMPTZ 필드를 두고 TTL 필드로 지정하면, 만료된 항목을 Milvus가 회수한다. 로그·세션처럼 수명이 있는 데이터에 유용하다.
  • 서버 측 집계·정렬: count, sum, avg, min, max 같은 SQL식 집계와 필드별 오름/내림차순 정렬을 서버에서 처리한다. 예전에는 클라이언트로 데이터를 가져와 직접 계산해야 했다.
  • 커스텀 사전·동의어: FileResource로 토크나이저 사전, 동의어 목록, 불용어, 복합어 분해 규칙을 등록해 BM25·analyzer·Text Match에 반영한다. 한국어처럼 사전 품질이 검색 품질에 영향을 주는 언어에서 중요하다.
  • EmbList와 DiskANN: 한 항목에 가변 길이의 벡터 리스트를 두고 디스크 기반으로 색인한다. 문서 하나를 여러 청크 벡터로 표현하는 RAG 패턴과 잘 맞는다.

우리 규모에선 어떤 게 실제로 와닿나

기존 글에서 정리한 결론은 "수천만 벡터·저부하 규모에선 속도가 아니라 기능이 전용 DB 를 쓰는 이유"였다. 3.0 을 이 관점으로 거르면, 화려한 것보다 다음 둘이 실질적이다.

  • 운영 컴포넌트 감소: Streaming Node 기본화와 Woodpecker zero-disk WAL은 작은 클러스터의 관리 대상을 줄여 준다.
  • 커스텀 사전(FileResource): 한국어 하이브리드 검색의 품질을 사전으로 다듬을 수 있어 도메인 용어가 많은 서비스에 유용하다.

반대로 External Collection·Storage V3 같은 레이크하우스 통합은 이미 대규모 데이터 레이크를 굴리는 조직에서 빛나는 기능이라, 소규모에선 당장 체감이 덜하다.

정리

3.0 은 beta 라 프로덕션에 바로 올릴 단계는 아니다. 변화의 방향은 운영 대상을 줄이고, 데이터 레이크와 통합하고, 스키마와 검색 기능을 확장하는 것으로 정리할 수 있다. "전용 벡터 DB 는 운영이 부담스럽다"와 "데이터를 또 복사해야 한다"는 두 가지 거부감을 정면으로 겨냥한 셈이다.

다음엔 Streaming Node 가 기본이 된 3.0 구조에서 데이터 입력·검색 흐름이 2.6 과 어떻게 달라지는지, External Collection 으로 S3 의 데이터를 실제로 zero-copy 검색하는 흐름을 직접 띄워 확인해 볼 생각이다.

참고 링크

  • Milvus Release Notes — 3.0-beta(2026.05.09) 기능 목록
  • Milvus Roadmap — 3.0 방향과 Vector Lake 계획
  • Use Woodpecker — zero-disk WAL
  • We Replaced Kafka/Pulsar with a Woodpecker for Milvus
  • Milvus Architecture Overview
on this page
  • 01세 갈래의 변화
  • 02운영 컴포넌트 감소
  • 03데이터를 복사하지 않는 데이터 레이크 통합
  • 04관계형 DB에 가까워진 스키마와 검색 표현력
  • 05우리 규모에선 어떤 게 실제로 와닿나
  • 06정리
  • 07참고 링크
tags
#study

이런 글도

  • db

    InnoDB 실행 계획이 바꾸는 잠금 순서: 같은 행을 고치는 두 UPDATE 가 가끔만 교착하는 이유

    2026.11.03
  • db

    gaps and islands: SQL 창 함수로 이어진 구간 찾기

    2026.10.30
  • db

    PostgreSQL 쿼리 패턴과 실행 계획: LATERAL 최신 한 건, unnest와 Inner Unique, gaps and islands

    2026.10.30
  • db

    PostgreSQL 실행 계획 읽기: Index Cond와 Filter, heap 접근, generic plan과 TimescaleDB 청크 제외

    2026.10.30

댓글 (0)