Faster embeddings: how we rebuilt the ONNX path in Manticore
TL;DR Highlight
Manticore Search가 기존 SentenceTransformers/Candle 백엔드를 ONNX Runtime으로 교체해 텍스트 임베딩 생성 속도를 평균 14배 향상시켰다. 별도 모델 서비스 없이 DB 내부에서 직접 임베딩을 처리하는 구조에서 INSERT 속도가 곧 임베딩 속도이기 때문에 이 개선은 실질적인 ingest 처리량 향상으로 직결된다.
Who Should Read
Manticore Search의 Auto Embeddings 기능을 사용 중이거나, CPU 환경에서 ONNX 모델로 임베딩을 빠르게 처리해야 하는 백엔드 또는 검색 시스템 개발자.
Core Mechanics
- Manticore Search의 Auto Embeddings는 별도 모델 서비스 없이 DB가 INSERT 시점마다 직접 임베딩 모델을 실행하는 구조라, 임베딩 생성 속도가 곧 INSERT 처리량과 동일하다.
- 기존 경로는 Hugging Face의 순수 Rust 기반 ML 추론 런타임인 Candle 위에 SentenceTransformers를 얹은 방식이었는데, 스레드 수나 배치 크기를 아무리 올려도 5~11 docs/sec 범위를 벗어나지 못했다.
- 새 경로는 ONNX Runtime(MiniLM, BGE, E5 같은 오픈소스 임베딩 모델 대부분이 이미 .onnx 파일로 배포하는 표준 포맷)을 직접 백엔드로 채택했고, Manticore Search 27.1.5부터 기본 경로로 적용됐다.
- 같은 서버(16코어/32스레드), 같은 모델(all-MiniLM-L12-v2), 같은 가중치 기준으로 전체 스레드 × 배치 조합을 평균 낸 결과 신규 ONNX 경로는 70~230 docs/sec를 기록해 약 14배 향상됐다.
- 단일 클라이언트 단일 INSERT 기준 latency는 약 14ms, 8개 동시 클라이언트 기준으로도 약 56ms로 기존 Candle의 200ms 이상 대비 크게 줄었다.
- 최대 bulk ingest 처리량을 원한다면 클라이언트 스레드를 늘리는 것보다 단일 스레드에 batch size 32~128을 사용하는 게 유리하다. 새 백엔드가 호출 내부에서 병렬 처리를 하므로 클라이언트 쪽 fan-out은 오히려 조율 오버헤드만 늘린다. 테스트 박스 기준 peak는 1스레드 + batch=64에서 233 docs/sec였다.
- 성능 개선을 가져온 핵심 변경 두 가지는 intra_op_spinning(모델 내부 연산자 간 스핀 대기) 비활성화, 그리고 워커 내부에서 문서를 배치로 묶는 로직을 포기한 것이다.
- API 변경은 없다. .onnx 파일을 제공하는 HuggingFace 모델을 이미 사용 중이면 자동으로 새 경로가 적용된다. 모델을 바꾸려면 FLOAT_VECTOR 필드의 MODEL_NAME 수정이 불가능해 테이블 전체 재생성은 필요 없지만, 새 컬럼을 추가해 임베딩을 재생성한 뒤 기존 컬럼을 삭제하는 방식으로 마이그레이션해야 한다.
Evidence
- CPU 환경에서는 배치 inference가 항상 유리하지 않다는 의견이 있었다. CPU는 GPU와 달리 대규모 병렬 처리를 위해 설계된 것이 아니라 배치가 오히려 느려질 수 있고, 대신 AVX512_BF16 명령어를 활용하면 기사 결과 대비 2~3배 추가 성능을 얻을 수 있다는 구체적인 제안이 나왔다. OpenVINO가 Intel CPU에서 이를 잘 지원하며 ONNX 모델을 OpenVINO로 변환하는 것도 어렵지 않다는 정보도 함께 공유됐다.
- all-MiniLM-L12-v2 모델이 사실상 업계 표준처럼 쓰이지만, 같은 연산량으로 더 좋은 임베딩 품질을 내는 대안 모델이 필요하다는 의견이 있었다. 더 큰 임베딩 모델에 Q4 양자화를 적용하는 방법이 있기는 하지만 ONNX와의 호환성이 불확실하다는 점도 언급됐다.
- CPU 추론 속도를 높이려는 사람에게 ONNX 전환을 첫 번째로 권장한다는 경험담이 공유됐다. 이는 본문의 결론과 일치하며, 실무에서도 ONNX 전환이 효과적임을 뒷받침한다.
- intra_op_spinning(스핀락) 비활성화가 핵심 개선이었다는 점에 대해, 스핀락은 '병렬 프로그래밍의 헤로인'이라는 표현과 함께 비판적인 댓글이 달렸다. 스핀락은 코어 전체를 독점한다고 선언하는 것과 같은데, 코어를 여러 프로세스가 공유하는 환경에서는 논리적으로 맞지 않으며 대부분의 경우(99%) 나쁜 선택이라는 주장이었다.
How to Apply
- Manticore Search에서 Auto Embeddings를 이미 사용 중이라면 버전 27.1.5 이상으로 업그레이드하는 것만으로 별도 설정 없이 ONNX 경로가 자동 적용되어 INSERT 처리량이 대폭 향상된다.
- 대량 데이터 ingest가 필요한 상황이라면 클라이언트 스레드 수를 늘리는 대신 단일 스레드에 --batch-size=32~64 옵션을 주는 방식으로 피크 처리량(약 233 docs/sec)을 끌어낼 수 있다. 클라이언트 fan-out은 새 백엔드의 내부 병렬화와 충돌해 오히려 손해다.
- 기존 테이블에서 임베딩 모델을 교체해야 하는 경우, FLOAT_VECTOR 필드의 MODEL_NAME 직접 수정은 불가능하므로 새 모델을 가리키는 컬럼을 추가 → 해당 컬럼 임베딩 재생성 → 기존 컬럼 삭제 순서로 마이그레이션하면 테이블 전체를 재생성하지 않아도 된다.
- CPU 환경에서 더 높은 추론 성능이 필요하다면 ONNX 전환 이후 추가로 OpenVINO 변환 및 AVX512_BF16 활용을 검토할 수 있다. 커뮤니티에서는 이 방법으로 ONNX Runtime 대비 2~3배 추가 속도 향상이 가능하다고 언급했다.
Terminology
Related Papers
Jamesob's guide to running SOTA LLMs locally
2천 달러짜리 RTX 3090 한 장부터 4만 달러짜리 RTX PRO 6000 4장 셋업까지, 로컬에서 최신 LLM을 직접 돌리는 방법을 하드웨어 선택·구성·실행 설정까지 통째로 정리한 실전 가이드다.
Asymmetric Quantization: Near-Lossless Retrieval with 97% Storage Reduction
멀티벡터 검색 모델의 문서 벡터를 1비트 이진값으로 압축하고 쿼리 벡터만 int8로 유지하는 비대칭 양자화 기법으로, 스토리지를 97% 줄이면서 검색 품질 손실을 0.61점(NDCG@10 기준)에 그치게 만든 실제 프로덕션 적용 사례다.
Show HN: Bash4LLM+ – A lightweight, dependency-free Bash wrapper for LLM APIs
Python이나 Node.js 없이 순수 Bash만으로 Groq 등 OpenAI 호환 LLM API를 호출할 수 있는 단일 스크립트 도구로, Termux(Android)를 포함한 모든 Unix 환경에서 동작한다.
Wayfinder Router: deterministic routing of queries between local and hosted LLM
프롬프트의 복잡도를 모델 호출 없이 오프라인으로 점수화해서 간단한 쿼리는 로컬 모델로, 어려운 쿼리는 유료 모델로 자동 라우팅하는 CLI 도구다. LLM 비용을 줄이면서도 응답 품질을 유지하고 싶은 개발자에게 유용하다.
Apple Neural Engine: Architecture, Programming, and Performance
Apple 기기에 내장된 AI 전용 칩인 ANE(Apple Neural Engine)를 리버스 엔지니어링으로 분석한 302페이지짜리 기술 문서로, Core ML 아래 숨겨진 내부 구조와 직접 접근 경로를 처음으로 공개한다.
DSpark: Speculative decoding accelerates LLM inference [pdf]
DeepSeek이 Speculative Decoding을 개선한 DSpark 기법을 공개했는데, 같은 시스템 용량 기준으로 사용자당 생성 속도가 57~78% 빨라졌다고 한다. 이게 DeepSeek이 경쟁사 대비 훨씬 싼 가격으로 Pro 모델을 제공할 수 있는 핵심 기술 중 하나일 가능성이 높다.