ANN을 Faiss처럼 만드는 것은 모두에게 맞는 것이 아니다

발행: (2026년 2월 2일 오후 08:19 GMT+9)
7 분 소요
원문: Dev.to

Source: Dev.to

(당신이 원하지 않았던 생존 가이드)

Faiss 같은 ANN 시스템을 만드는 건 어렵지 않다.
Faiss 같은 빠른 ANN 시스템을 만들면 지금까지 내린 모든 인생 선택을 의심하게 된다.

“벡터 검색이 얼마나 어려울까?” 라고 생각한다면… 축하한다—이 글이 바로 너를 위한 것이다.

Act 1: The Innocent Beginning (Python Era)

Python에서 시작한다.
Life is good – NumPy가 동작한다.

  • 정확도는 괜찮아 보인다.
  • 레이턴시는… 받아들일 만하다.

스스로에게 말한다: “그냥 프로토타입만 만들면 돼. 나중에 최적화하겠지.” – 전형적인 초보자 실수.

Act 2: “Let’s Rewrite It in C++” (Boss Music Starts)

어느 순간 쿼리가 느려지고, 금지된 말을 한다: “속도를 위해 C++로 다시 짜자.”

갑자기:

  • 논리를 디버깅하는 게 아니라 존재 자체를 디버깅한다.
  • Segfault, 정의되지 않은 동작, 메모리 충돌… 불법이라고 맹세할 정도의 이유들.
  • 버그 하나를 고치면 → 새로운 버그가 세 개씩 생겨난다.

Act 3: Speed‑Bound → Memory‑Bound (The Plot Twist)

처음엔 속도 제한이 있었다:

  • 나쁜 루프
  • 형편없는 데이터 레이아웃
  • 최적화되지 않은 수학 연산

이것들을 고치니 레이턴시가 떨어지고, 힘이 솟는다—하지만 더 이상 개선되지 않는다.

깨달음: 이제는 속도 제한이 아니라 메모리 제한이며, 여기서 진짜 고통이 시작된다.

Act 4: Milliseconds Matter (You Finally Understand Big Tech)

초는 쉬웠다. 밀리초는 전쟁이다.

  • 파일 하나를 바꾸면 → 레이턴시가 급등하고 QPS가 떨어진다.
  • 캐시 미스가 폭발한다.

배운 교훈

  • 캐시 미스는 수백 QPS를 잃게 할 수 있다.
  • 메모리 접근 레이턴시가 CPU 속도를 압도한다.
  • 데이터가 잘못된 위치에 있으면 “빠른 코드”는 의미가 없다.

Act 5: SIMD, AVX, OpenMP (False Hope Arc)

전력으로 달린다:

  • SIMD, AVX2/AVX‑512
  • OpenMP, BLAS
  • 손수 튜닝한 루프

현실이 다시 찾아온다:

  • 작은 배치 → OpenMP 오버헤드가 이득보다 크다.
  • 스레드가 캐시를 놓고 경쟁; 코어가 많다고 속도가 빨라지는 건 아니다.
  • 최적화가 이제는 또 다른 최적화를 필요로 한다.

Act 6: Python Bindings (New Boss, Same Pain)

“좋아, 파이썬 바인딩으로 그냥 노출하자.”

pybind11 + CMake 지옥에 오신 것을 환영합니다:

  • CMake가 pybind를 찾지 못하거나 거부한다.
  • 암호 같은 컴파일러 메시지.

추가 골칫거리:

  • 파이썬, C++, 그리고 NumPy 메모리 관리.
  • 리콜이 떨어지고, 속도가 거짓말한다.

NumPy 수학이 C++ 속도와 다르다는 것을 깨닫고 잠시 CPU를 창 밖으로 던지고 싶어진다.

Act 7: Scalar C++ Reality Check

순수 스칼라 C++을 시도한다.

놀라움: 잘 최적화된 NumPy/Cython이 순진한 C++보다 빠를 수 있다.

자존심이 Segfault한다.

이제는:

  • 데이터 정렬, 캐시 라인, 프리패칭을 배운다.
  • “그냥 C++만 쓰면 된다”는 말이 충분하지 않은 이유를 이해한다.

Final Act: The Faiss Reality Check

모든 튜닝—메모리, 캐시, 레이아웃, QPS, 레이턴시—을 마친 뒤 Faiss와 벤치마크를 해도 근소한 차이도 안 난다.

Faiss는 단순히 알고리즘이 아니라, 수년간의 저수준 고통, 튜닝, 그리고 메모리 마스터리이다.

Advice From Someone Who Survived (Barely)

Step 1: Python에서 시작한다.

  • 먼저 알고리즘을 만든다.
  • 정확도를 검증한다.
  • 충분히 좋다면 여기서 멈추고 행복해한다.

Step 2: 다음 경우에만 C++로 옮긴다:

  • 실제 메모리 한계에 부딪혔을 때.
  • 실제 레이턴시 한계에 부딪혔을 때.
  • 무엇을 감당하게 될지 충분히 이해했을 때.

Step 3: 최적화 지옥

  • SIMD, AVX, OpenMP (신중히)
  • 캐시를 고려한 설계
  • 메모리 우선 사고방식

이 단계에 도달한다면… 축하한다. 여기서부터 인생을 싫어하기 시작한다.

  • ANN 엔진을 만든다는 건 재미있다.
  • 빠른 ANN 엔진을 만든다는 건 고통이다.
  • Faiss와 경쟁하는 엔진을 만든다? 그건 보스전 마라톤이다.

여기까지 왔다면 – 존경한다. 🫡
시작하려는 생각이라면 – 경고했다.

이제 다시 벤치마크하고 캐시 미스 때문에 울 일이다.

그래서… 이미 절반은 끝났다. 아직 끝나지 않은 일들이 있다. ANN이 온다. 오픈소스로 공개될 것이다—“곧™”이 아니라 “스타트업 곧”. 하지만 곧—코드는 이미 존재하고 고통은 이미 치러졌다.

Back to Blog

관련 글

더 보기 »