Какой движок выдержит 50 миллионов векторов размерности 768, если отрубить облако и заставить работать на вашем собственном железе с жестким лимитом по RAM? Ответ «pgvector» принимается только от тех, кто не видел продакшена под реальным трафиком. База на PostgreSQL отличная, но на 10 миллионах записей она ложится по памяти и latency так, что никакой тюнинг не спасает — индексы распухают, поиск деградирует. Эту тему мы уже закрыли в прошлом разборе.
В Morana Labs мы строим индустриальный ИИ. Это reinforcement learning для робототехники, хардкорный edge-инференс, компьютерное зрение и высоконагруженный поиск в закрытых контурах. Данные не покидают периметр клиента. Когда возникает задача масштабирования поиска для RAG на десятки миллионов документов, красивые SaaS-решения вроде Pinecone отваливаются мгновенно из-за 152-ФЗ, санкций и политик безопасности. Остается голая инженерия: выбор движка под локальную стойку, где серверы стоят реальных денег, а GPU почти всегда в дефиците.
Qdrant vs Milvus vs Weaviate vs Elasticsearch на 50 млн векторов on-prem: RPS, p99 и recall@10
Мы прогнали четыре специализированных движка голова-в-голову. Одинаковый датасет на 50 млн записей, одинаковое железо (два сервера по 64 ядра, 256 RAM, быстрые NVMe), жесткий таргет по RPS и p99. В README на GitHub все они обещают миллионы QPS. В проде иллюзии рушатся. Elasticsearch с его kNN-плагином удобен, если у вас исторически развернут ELK-стек. Но на векторном поиске он жрет оперативку как не в себя. Под плотным потоком запросов p99 улетает за 150 миллисекунд, а GC-паузы в Java заставляют клиентов отваливаться по таймауту. Weaviate показывает прекрасную эргономику и REST API, но его реализация сборки графа на лету обходится слишком дорого по CPU при интенсивной записи. В финал тяжелого веса выходят Qdrant и Milvus.
Память против качества: HNSW, IVF и ловушки квантования
Голый HNSW на 50 миллионов эмбеддингов 768-d потребует почти 200 гигабайт RAM. Это больно. Вы не можете просто забить всю память графом, операционная система убьет процесс через OOM killer при первом же скачке потребления. Спасает квантование. И тут начинаются радикальные отличия. Milvus с IVF_PQ дает запредельную плотность упаковки: сжатие через Product Quantization в 8-16 раз. Звучит отлично, пока вы не измеряете метрику качества. На PQ recall@10 пробивает дно, падая с эталонных 0.98 до 0.82. Поиск превращается в генератор случайных чисел. Qdrant пошел другим путем: скалярное квантование до int8 с выносом самих векторов на диск, оставляя в RAM только граф навигации. Это позволяет держать recall на уровне 0.95-0.96, утилизируя всего 45 гигабайт памяти. Разница колоссальная.
{ "vectors": { "size": 768, "distance": "Cosine", "on_disk": true }, "hnsw_config": { "m": 16, "ef_construct": 100, "full_scan_threshold": 10000 }, "quantization_config": { "scalar": { "type": "int8", "always_ram": true } } } Фильтрация по метаданным и шардинг
Фильтрация убивает все синтетические бенчмарки. Post-filter — это выстрел в ногу: вы нашли топ-10 векторов, а потом отсеяли девять по условию наличия нужного тега. Итог — пустая выдача. Нужен строгий pre-filter. Milvus делает это через bitsets, Qdrant использует кастомный payload-индекс. На сложных запросах с кардинальностью фильтров движок на Rust вырывается вперед, пропуская ненужные ветки HNSW-графа без деградации latency. Шардинг тоже не прощает ошибок. Кластер обязан пережить падение ноды без потери качества выдачи. Если выдернуть питание из сервера Milvus, архитектура с жестким разделением storage и compute спасет данные в MinIO, но перестроение кэша на другой ноде уронит p99 на минуты. Qdrant просто переключит чтение на реплику. Гладкая деградация без потери recall.
Апдейты на лету и OOM-катастрофы
Апдейт 1 миллиона векторов на живой базе вскрывает архитектурные гнилушки. Elasticsearch начинает истерично плодить сегменты и мерджить их в фоне, укладывая дисковую подсистему в пол. Qdrant переваривает батчи за счет фоновой оптимизации, не блокируя чтение. Но эксплуатация — это боль. В одном из внедрений мы словили жесткий OOM при апгрейде мажорной версии. Причина банальна: старая версия держала mmap на терабайтном диске, а новая логика миграции попыталась прогреть весь граф в RAM. Сервер просто захлебнулся. Резервное копирование терабайтов векторных индексов — это вам не SQL-дамп сделать. Нам пришлось переписывать пайплайн бэкапов на инкрементальные снапшоты, чтобы обновляться без даунтайма.
Вывод: матрица выбора под вашу стойку
Нужен enterprise-комбайн для сотен миллионов векторов с горизонтальным масштабированием команд разработчиков — берите Milvus. Но готовьтесь держать DevOps-штат для обслуживания зоопарка из etcd, Pulsar и MinIO. Нужно уложить 50 миллионов записей на пару серверов, получить 2500 RPS, выдержать p99 ниже 20 миллисекунд и сохранить сложную мета-фильтрацию — ставьте Qdrant. Если данные уже лежат в ELK и векторов не больше пары миллионов — включайте kNN в Elasticsearch и не плодите лишние сущности. Никакой магии. Только профиль нагрузки, честные тесты и стоимость владения.