Мы потратили 8 лет на то, чтобы сделать векторные базы данных быстрее. А потом остановились.
Стоимость имеет значение. Так было всегда. Но есть порядок: снижать затраты можно только после того, как достигнута планка производительности. Система, которая стоит дешево, но возвращает неправильные результаты, бесполезна. Как и система, которая не может удерживать задержку под нагрузкой.
Milvus был открыт как open source в 2019 году с простой убежденностью: векторные базы данных станут ключевой инфраструктурой данных, а не функцией, спрятанной внутри приложения. Более восьми лет эта убежденность вела нас в одном направлении: делать векторный поиск быстрее и предсказуемее. Сжатие индексов, планирование сегментов, настройка HNSW, стратегии предвыборки — почти каждая крупная оптимизация была направлена на одно и то же: поместить данные в локальный кеш и искать быстрее.
Эта работа по-прежнему остается фундаментом. Always-on serving — правильная архитектура для рабочих нагрузок векторного поиска с высоким QPS и низкой задержкой. Если коллекция запрашивается постоянно, держать индексы в памяти — не расточительство, а стоимость обеспечения продуктового опыта.
Затем мы обратились к стоимости. Многоуровневое хранение помогло — горячие сегменты в памяти, холодные данные на диске и в объектном хранилище, реальная экономия. Но узлы никогда не выключались. Для рабочей нагрузки, которая выполняется пять часов в месяц, вы все равно платили за остальные 715.
Этот разрыв — одна из проблем, для решения которых создан новый Zilliz Vector Lakebase. Более крупный сдвиг заключается не просто в том, чтобы «сделать векторный поиск дешевле». Он в том, чтобы позволить постоянным семантическим данным поддерживать более одного жизненного цикла вычислений: always-on serving, когда важны задержка и пропускная способность, и вычисления по требованию, когда данные должны оставаться доступными для запросов, но не требуют выделенных машин, работающих весь месяц.
Физика, стоящая за моделью always-on serving
Задержка чтения из S3 составляет 20–50 мс на запрос. Обход графа HNSW затрагивает сотни узлов на запрос. Соедините эти две цифры, и вывод очевиден: векторные индексы должны находиться в локальной памяти, чтобы обслуживать запросы. Это не недостаток дизайна — это физика.
Чтобы сделать это конкретным: 100 млн векторов, 768 измерений, float32. Сырые векторные данные занимают ~286 ГБ; граф HNSW (M=48) добавляет еще ~55 ГБ в виде ссылок на соседей — всего примерно 340 ГБ.
Традиционная модель Milvus QueryNode:
┌──────────────────────────────────────────────────────────────┐
│ Традиционная архитектура Milvus │
│ │
│ 100M × 768-dim float32 → ~340 GB, разделенные на 3 QueryNodes │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ QueryNode 1 │ │ QueryNode 2 │ │ QueryNode 3 │ │
│ │ 128GB RAM │ │ 128GB RAM │ │ 128GB RAM │ │
│ │ + NVMe │ │ + NVMe │ │ + NVMe │ │
│ │ seg 0-99 │ │ seg 100-199 │ │ seg 200-299 │ │
│ │ (~113 GB) │ │ (~113 GB) │ │ (~113 GB) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ load() │ load() │ load() │
│ └─────────────────┼─────────────────┘ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ S3 (источник истины) │ │
│ │ полный набор данных 340 GB │ │
│ └───────────────────────┘ │
│ Коллекция доступна для запросов только после загрузки всех 340 GB │
│ Сбой узла → его сегменты недоступны → перезагрузка из S3 │
└──────────────────────────────────────────────────────────────┘
Каждому сегменту нужен резидентный узел, прежде чем коллекция станет доступной для запросов. 340 ГБ данных, три машины по 128 ГБ, работающие 24/7. Для часто запрашиваемых коллекций это работает хорошо. Затем ИИ изменил паттерн спроса.
Команды продуктов проводят двухнедельные A/B-эксперименты, после которых к этим эмбеддингам больше никогда не обращаются. В SaaS-продуктах 90% пользователей не входили в систему на прошлой неделе. В базах знаний RAG 80% документов не извлекались за последний месяц. Данные не бесполезны — к ним могут обратиться в любой момент, — но обращаются к ним редко. Традиционные базы данных справляются с этим с помощью многоуровневого хранения: горячие данные в памяти, холодные данные на диске и подгрузка страниц по требованию. В векторных базах данных такого понятия не было. Либо вы загружали всю коллекцию, либо она была недоступна для запросов.
До того как AI-генерируемые эмбеддинги получили широкое распространение, такая бинарность не была проблемой. Большинство векторных нагрузок были либо явно онлайн-системами обслуживания, где имело смысл держать индексы постоянно в памяти, либо офлайн-экспериментами, которые могли мириться со специализированными пайплайнами. AI изменил эту промежуточную область.
Мы начали замечать этот сдвиг в разговорах с клиентами. Эмбеддинги больше не просто обеспечивали работу production RAG-чатботов. Мировой лидер в области GPU преобразовывал в эмбеддинги данные автономного вождения — кадры с камер, поездки, погоду, местоположение, временные метки и другие метаданные, — чтобы инженеры могли находить редкие сценарии вождения среди десятков миллиардов векторов. Компания в сфере образовательных технологий использовала семантический поиск для многоязычного выявления плагиата, где нагрузки могли колебаться от нескольких документов до 10 000+ документов в пакете в периоды экзаменов.
Это и есть контекст для Vector Lakebase. AI-команды накапливают неструктурированные данные, которые должны оставаться постоянными и обнаруживаемыми, но характер доступа к ним неравномерен. Одни пути требуют непрерывного обслуживания. Другим нужен эпизодический поиск, исследование или пакетное обнаружение по тем же базовым данным. Рассматривать все эти пути как постоянно включенное обслуживание означает оставлять слишком много инфраструктуры без дела.
Пользователь написал в нашем community Slack:
"Мои эмбеддинги уже в S3. Вы говорите мне, что мне нужно потратить три часа на их импорт, держать три машины с 128 GB RAM работающими 24/7 и платить $24,000 в год — только чтобы запускать эпизодические запросы?"
Он был прав. Проблема была не в том, где находились данные, и не в том, был ли индекс достаточно быстрым. Он платил по ценам горячих данных за паттерн доступа к холодным данным: 0,7% активно, 100% оплачивается.
Рынок уже начал доказывать, что экономика, ориентированная прежде всего на объектное хранилище, имеет значение для векторных нагрузок. А держать stateless-вычисления поверх объектного хранилища было направлением, которого хотели многие пользователи. Но более сложный вопрос для нас заключался в том, как встроить эту модель затрат в полноценную векторную базу данных: с поиском с фильтрами, семантикой базы данных, операционной изоляцией и путем, который всё ещё связывает это обратно с постоянно включенным обслуживанием, когда нагрузки становятся горячими.
Таков наш тезис Vector Lakebase: хранить семантические данные постоянно и позволять вычислительному слою соответствовать нагрузке. Поиск по требованию — одно из выражений этой архитектуры. Чтобы сделать его правильно, потребовалось преодолеть четыре технических препятствия.
Четыре барьера для поиска по требованию в Lakebase
В модели поиска по требованию Lakebase QueryNodes запускаются по требованию, обслуживают запросы, затем освобождаются. Данные остаются в объектном хранилище как источник истины. Вычисления масштабируются до нуля между сессиями запросов. Звучит просто, но чтобы сделать это пригодным к использованию, нужно было решить проблемы задержки холодного старта, объема сканирования, усиления I/O при извлечении и фиксированных затрат control plane.
Холодный старт был слишком медленным
340 GB индекса HNSW. Загрузка из S3: более четырех минут. Четыре минуты холодного старта убивают любой сценарий использования по требованию. Пользователь запускает запрос и ждет четыре минуты — это не задержка, это сломанный продукт.
Решение заключалось в том, чтобы сжать индекс, сохранив его пригодным к использованию. Мы построили 1+3-битное matryoshka-квантование на основе RabitQ (Gao & Long, 2024). Два слоя, вложенные как матрешки.
1-битный слой загружается первым — 13 GB вместо 340 GB. Поиск запускается на нем сразу: RabitQ дает доказуемую границу ошибки для 1-битных расстояний, поэтому можно безопасно отсекать кандидатов и гарантировать, что ничего из истинного top-k не будет отброшено. 85–90% recall на первом запросе.
3-битный слой загружается в фоне, пока выполняется 1-битный поиск. Когда он готов, он используется как проход уточнения — кандидаты, прошедшие 1-битный этап, пересчитываются с полной точностью 1+3 бита. Recall достигает 95%+. Эти два слоя — не альтернативы; внутренний выполняет фильтрацию, а внешний улучшает результаты.
Сырая пропускная способность квантования — узкое место в масштабе. Ускоренная на GPU сборка индекса и query kernels на AVX512 / ARM SVE доводят пропускную способность вычисления расстояний до уровня, при котором накладные расходы квантования становятся пренебрежимо малыми. Еще два улучшения повышают recall: оптимальное масштабирование для каждого вектора, при котором у каждого вектора минимизируется собственная ошибка квантования, а не используется общий коэффициент; и неравномерное распределение битов по измерениям на основе дисперсии, чтобы измерения с высокой плотностью информации получали больше битов. Оба напрямую уменьшают ошибку квантования без увеличения размера индекса.
Первое препятствие устранено. Но даже при полной квантизации сканирование 100M векторов все еще дорого.
Сканирование 100M векторов
1-битный индекс мал, но вычисление расстояний по 100M векторам все еще линейно. В модели по запросу это усугубляется: более длительное время вычислений означает, что QueryNode дольше остается резидентным, что сужает окно для эластичного освобождения.
IVF-кластеризация с глобальным отсечением индекса (число бакетов масштабируется с объемом данных):
┌──────────────────────────────────────────────────────────────┐
│ Глобальный индекс + IVF-отсечение │
│ │
│ 100M векторов → IVF-кластеризация (N бакетов, N │
│ масштабируется с │
│ объемом данных) │
│ │
│ ┌───┬───┬───┬───┬───┬───┬───┬───┬─── ··· ───┬───┐ │
│ │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ │ N │ │
│ └───┴───┴───┴───┴───┴───┴───┴───┴─── ··· ───┴───┘ │
│ ▲ ▲ ▲ │
│ █ █ █ ← сканировать только ~3%│
│ │
│ Запрос q → найти ближайшие центроиды → искать в этих бакетах│
│ │
│ Просканированные данные: ~3% от общего объема │
│ S3 I/O: загрузить ~3% данных │
│ Вычисления: расчет расстояний только на ~3% │
└──────────────────────────────────────────────────────────────┘
IVF — не новинка, но две вещи делают нашу реализацию другой.
Во-первых, масштаб. Большинство реализаций IVF разваливаются на масштабе в миллиард векторов, потому что для построения индекса требуется загрузить все в память сразу. Мы создали распределенное построение индекса, которое шардирует работу кластеризации по узлам — IVF в любом масштабе, включая миллиарды векторов.
Во-вторых, взаимодействие с Lakebase. Во время запроса из S3 загружаются только релевантные бакеты. Проверить ~3% кластеров, получить ~3% данных, удерживать ~3% в памяти QueryNode. Узел, загрузивший только 3% датасета, можно освободить почти сразу после завершения запроса.
Вместе с 1-битным квантованием эти два барьера перемножаются: 340 GB → 13 GB (квантование) → ~400 MB на запрос (IVF-отсечение). Cold start загружает только центроиды кластеров и метаданные 1-битного индекса — 5–10 секунд. Каждый последующий запрос получает только релевантные бакеты, а не полные 13 GB.
Второе препятствие устранено.
Retrieve усиливал S3 I/O
Векторный поиск возвращает IDs, а не сырые данные. Получение исходных векторов или скалярных полей означает второй раунд чтений, и в storage-native пути запроса каждое из них является точечным чтением из S3.
Проблема была в формате хранения. Стандартные файлы Parquet используют группы строк по 64 MB. Одна векторная запись занимает около 3 KB. Прочитать ее означает скачать всю группу строк: 3 KB полезных данных, 64 MB фактического I/O — усиление примерно в 20 000 раз. Терпимо на локальном диске. Жестко для S3.
Storage V2 справился с половиной проблемы: разделил широкие и узкие столбцы, при этом векторы и скалярные поля хранятся независимо, а группы строк уменьшены до 1 МБ — в 64 раза меньше избыточного чтения. Но есть нюанс: блочное сжатие Parquet опирается на большие группы строк. Уменьшите их — и сжатие ухудшается; файлы становятся больше. Малые группы строк и хорошее сжатие в Parquet взаимоисключают друг друга. И здесь появляется Vortex.
Vortex, разработанный Spiral и размещённый в Linux Foundation, имеет полностью настраиваемую компоновку без принудительной структуры групп строк; прямые точечные запросы по сжатым данным через вложенное кодирование Delta → RLE → BitPacking без необходимости распаковки; и автоматический выбор кодирования на основе алгоритма BtrBlocks, который балансирует коэффициент сжатия, скорость кодирования и скорость декодирования.
Бенчмарки: 3 млн строк, 128-мерные векторы, S3, 256 параллельных читателей, пакет по 10 строк на чтение.
| Метрика | Parquet | Lance | Vortex |
|---|---|---|---|
| Пропускная способность точечного чтения (чтений/с) | 162 | 464 | 620 |
| Байты S3 на чтение (МБ) | 9.44 | 0.006 | 0.07 |
| S3 GET на строку | ~2 | ~5 | ~2 |
| Пропускная способность полного сканирования (МБ/с) | 638 | 730 | 1,548 |
| Пропускная способность записи (МБ/с) | 216 | 247 | 244 |
Parquet загружает 9.44 МБ на одно чтение — всю группу строк. Lance снижает это до 0.006 МБ за счёт чтения с гранулярностью 512 байт, но платит за это IOPS: ~5 S3 GET на строку против ~2 у остальных. Vortex достигает 0.07 МБ с ~2 GET на строку — в 135 раз меньше трафика, чем Parquet, без штрафа по IOPS. Пропускная способность полного сканирования в 2.4 раза выше, чем у Parquet; записи сопоставимы.
Третье препятствие устранено.
Затраты на control plane не масштабировались до нуля
Первые три изменения были в пути выполнения запросов. Четвёртое было скрыто в control plane.
Даже когда все QueryNode простаивают, каждый экземпляр Milvus поддерживает свои Coordinator и etcd в рабочем состоянии. N tenants означает N sets. QueryNode могли масштабироваться до нуля; эти два компонента не могли — они stateful и должны оставаться резидентными. При миллионе tenants накладные расходы control plane превышают стоимость QueryNode.
Control plane Lakebase меняет это с O(N) на O(1):
Традиционный Milvus: стоимость control plane O(N)
┌──────────────────────────────────────────────────────────────┐
│ Shared infrastructure │
│ Kafka / Pulsar (shared) Index Pool (shared) │
└──────────────────────────────────────────────────────────────┘
| | |
Tenant A Tenant B Tenant C
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Coordinator │ │ Coordinator │ │ Coordinator │
│ etcd │ │ etcd │ │ etcd │
├──────────────────┤ ├──────────────────┤ ├──────────────────┤
│ QueryNode │ │ QueryNode │ │ QueryNode │
│ (dedicated) │ │ (dedicated) │ │ (dedicated) │
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
└─────────────────────┼─────────────────────┘
↓
┌──────┐
│ S3 │
└──────┘
Lakebase: стоимость control plane O(1)
┌───────────────────────────────────────────────────────────────┐
│ Общая плоскость управления (на регион) │
│ │
│ ┌──────────────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │ Общий │ │ Каталог │ │ WAL Service │ │
│ │ координатор │ │ ≠ etcd │ │ → S3, ≠ Kafka │ │
│ │ │ │ │ │ │ │
│ └──────────────────┘ └──────────┘ └───────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Index Service (пул сборки GPU) │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────┬─────────────────────────────────┘
┌────────────────────┼─────────────────────┐
NS арендатора A NS арендатора B NS арендатора C
┌────────────┐ ┌────────────┐ ┌───────────┐
│ QueryNode │ │ (простой) │ │ QueryNode │
│ QueryNode │ │ scale = 0 │ └────┬──────┘
└──────┬─────┘ └────────────┘ │
└─────────────────────┬─────────────────────┘
↓
┌──────┐
│ S3 │
└──────┘
Lakebase заменяет каждый элемент старой модели «на арендатора». Координатор является общим для всех арендаторов, заменяя координаторы на каждого арендатора. Catalog заменяет etcd на каждый экземпляр и снимает ограничение хранилища в 2 ГБ. WAL Service пишет напрямую в S3 без локального диска — измеренная пропускная способность 750 МБ/с, в 5,8 раза быстрее Kafka — заменяя Kafka/Pulsar. Index Service — это пул сборки GPU, общий для арендаторов, заменяющий выделение GPU на каждый экземпляр.
«Scale to zero» перестает означать «QueryNodes могут освобождаться» и начинает означать «весь экземпляр почти ничего не стоит в простое».
┌──────────────────────────────────────────────────────────────┐
│ Multi-tenant × Lakebase On-demand Search │
│ │
│ слой хранения S3 вычисления (по требованию)│
│ ┌──────────────┐ │
│ │данные арендатора A│ ◄──── запрос ──── QueryNode A (активен)│
│ ├──────────────┤ │
│ │данные арендатора B│ (простой, нет QueryNode)│
│ ├──────────────┤ │
│ │данные арендатора C│ (простой, нет QueryNode)│
│ ├──────────────┤ │
│ │данные арендатора N│ ◄──── запрос ──── QueryNode N (активен)│
│ └──────────────┘ │
│ │
│ 1 млн арендаторов, 1% активны → 99% данных имеют нулевую стоимость вычислений│
└──────────────────────────────────────────────────────────────┘
Традиционно мультитенантность означала совместное использование кластера несколькими арендаторами через отдельные коллекции или партиции — но у такого кластера были жесткие потолки: лимит метаданных etcd в 2 ГБ, пропускная способность координатора и фиксированная емкость QueryNode. Масштабирование за пределы этих ограничений означало больше кластеров, а значит — больше накладных расходов.
Lakebase меняет этот потолок. Catalog заменяет etcd масштабируемым хранилищем метаданных, а общий координатор обслуживает гораздо больше арендаторов без накладных расходов на каждого арендатора. S3 обеспечивает эластичность хранения. В результате получается единый кластер, способный обслуживать гораздо больше изолированных арендаторов — и только арендаторы, активно получающие запросы, потребляют вычислительные ресурсы. Остальные платят только за хранение.
Вернемся к тому пользователю из Slack
Тот же сценарий: 100 млн векторов, 768-мерные float32, 10 запросов в день, по одной минуте каждый. Активность ~5 часов в месяц.
Для этой рабочей нагрузки важное отличие заключается не только в том, где находятся байты. Важно то, должен ли compute оставаться привязанным к этим байтам, пока никто их не запрашивает.
И время холодного старта self-hosted Milvus, и tiered storage model в Zilliz Cloud — это разовые затраты на загрузку: после прогрева запросы выполняются быстро. Холодный старт Lakebase on-demand происходит в начале каждой сессии после того, как нода масштабируется обратно до нуля, что для этой рабочей нагрузки, по сути, происходит каждый раз. 5–10 секунд на сессию — это компромисс за то, что между сессиями вы ничего не платите.
Стоимость self-hosted в основном состоит из постоянно включенного EC2: 3 × r6g.4xlarge on-demand примерно за $2,073/месяц, плюс Kafka. Zilliz Cloud tiered storage model снимает операционную нагрузку, но модель биллинга остается той же. Lakebase on-demand search меняет модель: вы платите только за те пять часов, которые действительно используете.
| Self-hosted Milvus | Zilliz Cloud Tiered Storage Model | Lakebase On-demand Search | |
|---|---|---|---|
| Жизненный цикл compute | Всегда включен | Всегда включен | По требованию |
| Стоимость compute в простое | Полная ставка | Полная ставка | $0 |
| Паттерн холодного старта | Разовая загрузка, затем прогрето | Разовая загрузка, затем прогрето | 5–10 с в начале сессии |
| Лучший сценарий | Горячие serving-нагрузки | Управляемое hot/cold tiering | Редко запрашиваемые семантические данные |
~$240/год. Нулевая стоимость compute 99% времени. Четыре препятствия, четыре уровня изменений.
Физика не изменилась. S3 по-прежнему дает 20–50 мс на чтение.
Изменилась модель compute вокруг этой физики: tiered storage снизил стоимость хранения более холодных данных, но Lakebase on-demand search убирает нижнюю границу постоянно включенного compute для рабочих нагрузок, которые в основном простаивают.
Этот разрыв важнее, чем сама экономия. Пользователь Slack, который не мог оправдать $24,000/год, не просто сэкономил деньги после перехода — он начал индексировать больше данных, потому что поиск стал достаточно дешевым, чтобы делать его больше. Ниже цена — выше спрос.
В этом и заключается более широкая история Vector Lakebase. Когда семантические данные могут существовать независимо от одного постоянно включенного serving-кластера, команды могут выбирать форму compute, соответствующую рабочей нагрузке: непрерывный serving для горячих путей, on-demand search для редко запрашиваемых данных и batch compute для задач discovery или обработки.
Zilliz Vector Lakebase доступен в public preview
Мы запустили public preview Zilliz Vector Lakebase — крупную эволюцию Zilliz Cloud от управляемой векторной базы данных к единой платформе семантических данных, сочетающей low-latency vector serving с открытостью, масштабируемостью и экономикой data lake.
Ключевые возможности Vector Lakebase:
- Tiered serving, оптимизированный для разных компромиссов между производительностью в реальном времени и стоимостью
- On-demand search для крупномасштабных или исследовательских рабочих нагрузок без постоянно включенного compute
- External data lake search — индексируйте и выполняйте поиск напрямую по вашим существующим данным в lake
- Full-spectrum search по векторам, тексту, JSON и геопространственным данным с hybrid retrieval и reranking
- Unified lake-native storage на базе Vortex, открытого формата с более быстрыми и дешевыми random reads, чем Lance или Parquet
Если ваш текущий стек разделяет serving и discovery на отдельные системы, возможно, стоит присмотреться к Vector Lakebase. Попробуйте его в Zilliz Cloud — новые регистрации с рабочей почтой получают $100 бесплатных кредитов — или свяжитесь с нами, чтобы обсудить ваш сценарий использования.
Читать далее

Introducing Zilliz Cloud Global Cluster: Region-Level Resilience for Mission-Critical AI
Zilliz Cloud Global Cluster delivers multi-region resilience, automatic failover, and fast global AI search with built-in security and compliance.

DeepSeek-OCR Explained: Optical Compression for Scalable Long-Context and RAG Systems
Discover how DeepSeek-OCR uses visual tokens and Contexts Optical Compression to boost long-context LLM efficiency and reshape RAG performance.

Why I’m Against Claude Code’s Grep-Only Retrieval? It Just Burns Too Many Tokens
Learn how vector-based code retrieval cuts Claude Code token consumption by 40%. Open-source solution with easy MCP integration. Try claude-context today.



