MAATRIX / Блог / Сколько RAM нужно для векторной базы: расчёт

Сколько RAM нужно для векторной базы: расчёт

Сколько RAM нужно для векторной базы: расчёт

MAATRIX

«Сколько нужно RAM» для векторной базы обычно узнают постфактум: контейнер уходит с кодом 137 на первой крупной заливке, а на форуме отвечают «у нас взлетело на 8 ГБ», не называя ни размерность вектора, ни движок. Память под векторный индекс считается заранее и без бенчмарков — у неё простая арифметика, почти одинаковая для Qdrant, Milvus, Weaviate, Chroma и pgvector. Разберём формулу по частям, сравним, во что упирается каждый движок ещё до первой точки, и посчитаем, сколько векторов поместится в 4, 8, 16, 32 и 64 ГБ.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Почему «сервер с запасом» не работает

Типичная ошибка сайзинга — считать по объёму исходных данных, а не по числу векторов. «У меня 50 ГБ документов» ничего не говорит о памяти базы: значение имеет не вес текста, а сколько из него получится чанков. Те же 50 ГБ при чанках по 500 символов дают около 100 миллионов кусков, при чанках по 4000 символов — 12,5 миллиона: разница в восемь раз, и именно она определяет память.

Вторая ошибка — брать тариф «с запасом» не считая, потому что «векторные базы прожорливые»: одни движки экономнее других в разы, и без расчёта неясно, в какую сторону промахнётесь — переплатой за пустые гигабайты или процессом, убитым ядром. Сигнатура второго случая почти не зависит от движка. В dmesg или journalctl -k:

Out of memory: Killed process 18420 (qdrant) total-vm:6812448kB, anon-rss:5104216kB, file-rss:0kB

в логе systemd:

systemd[1]: weaviate.service: A process of this unit has been killed by the OOM killer.
systemd[1]: weaviate.service: Main process exited, code=killed, status=9/KILL

Docker возвращает код выхода 137, а docker inspect <container> --format '{{.State.OOMKilled}}'true. Момент предсказуем: не на пустой коллекции, а на первой крупной заливке или на фоновом перестроении индекса, когда к статичному расходу добавляется временный пик.

Универсальная формула: сколько памяти нужно на один вектор

У большинства движков в основе один и тот же алгоритм — HNSW (Hierarchical Navigable Small World), и его память раскладывается на две предсказуемые части.

Сырой вектор. размерность × байт_на_координату. Точность хранения задаёт множитель:

ТипБайт на координатуВектор на 1024 измерения
float3244096 байт
float16 / bfloat1622048 байт
int8 (скалярное квантование)11024 байта
binary1/8128 байт

Граф HNSW. На нулевом слое у точки до M × 2 связей, каждая хранится как 4-байтный идентификатор соседа: M × 2 × 4 байт на точку, верхние слои добавляют единицы процентов сверху. У Qdrant и Milvus параметр называется m и по умолчанию равен 16, что даёт 128 байт графа на точку; у pgvector то же имя и то же значение по умолчанию с версии 0.5.0, когда в него добавили HNSW. Конструкция графа у остальных движков идентична, но дефолт может отличаться — сверяйтесь с документацией своего движка перед расчётом, а не берите чужой множитель.

Итоговая формула на точку:

байт_на_точку ≈ размерность × байт_на_координату + M × 2 × 4

Пример: 1 миллион точек, размерность 1024, float32, M = 161024 × 4 + 128 = 4224 байта на точку, на миллион около 4,22 ГБ. Это вектор и граф без payload, без памяти самого движка и без запаса на пики.

Payload и метаданные считаются отдельно. Текстовый чанк на 1000–1500 символов в UTF-8 — полтора-два килобайта, и на миллионе записей это легко перевешивает сами векторы при небольшой размерности. Держать payload в памяти или выносить на диск — отдельная настройка почти у каждого движка, и про неё забывают именно потому, что она не входит в формулу выше.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Таблица: сколько векторов поместится в 4, 8, 16, 32 и 64 ГБ памяти

Обратный расчёт часто полезнее прямого: тариф сервера известен заранее, а сколько эмбеддингов получится из корпуса — нет. Методика простая: из RAM вычитаем 1 ГБ на систему, оставшееся делим на 1,3 — запас на пики при перестроении и рост коллекции, — и делим на байты на точку по формуле выше.

RAM384 измерения1024 измерения1536 измерений
4 ГБ1,39 млн546 тыс368 тыс
8 ГБ3,24 млн1,27 млн859 тыс
16 ГБ6,93 млн2,73 млн1,84 млн
32 ГБ14,3 млн5,65 млн3,80 млн
64 ГБ29,1 млн11,5 млн7,73 млн

Гигабайты здесь десятичные, 10⁹ байт. 384 измерения — это all-MiniLM-L6-v2, компактная модель для прототипов; 1024 — типичная размерность bge-m3, multilingual-e5-large, Cohere Embed v3 и Voyage-3; 1536 — text-embedding-3-small от OpenAI и старый ada-002. Таблица считает только вектор и граф — прибавьте payload и держитесь нижней границы диапазона, если он не вынесен на диск.

Не только векторы: во что упирается конкретный движок ещё до первой точки

Формула на точку почти одинакова везде, а входной билет — нет. Пять движков, с которыми чаще всего работают RAG-проекты, стоят по-разному ещё на пустой коллекции.

ДвижокАрхитектураМинимум «с нуля»Диск вместо RAMКвантование
Chromaодин процесс (ядро на Rust с релиза 1.0, апрель 2025)2 ГБ RAMнет, граф целиком в RAMнет
Qdrantодин процесс (Rust)4 ГБ RAMда, on_disk и mmapint8, product, binary
Weaviateодин процесс (Go)4 ГБ RAMограниченноPQ, BQ
Milvus standalone3 контейнера: сервис, etcd, объектное хранилище8 ГБ RAM — требование документациида, mmap с версии 2.4скалярное, PQ
pgvectorрасширение Postgres, отдельного процесса нетстолько, сколько и так требует Postgresкак сам Postgres — страничный кеш ОСhalfvec, bit с версии 0.7.0

«Минимум с нуля» — это память, которую движок просит на пустой базе. Для Milvus это не перестраховка: документация прямо просит 4 ядра, 8 ГБ RAM и 100 ГБ диска на standalone, потому что загруженная коллекция целиком читается в память. В кластерном режиме добавляются Pulsar или Kafka, отдельный кластер etcd и роли нод — query, data, index, proxy: служебный слой суммарно съедает десятки гигабайт ещё до первого вектора — для одного сервера это почти всегда лишнее.

pgvector — особый случай: если Postgres уже поднят под основные данные, отдельного налога на векторную базу нет, только дополнительный расход RAM на сам индекс внутри shared_buffers и кеша ОС. Обратная сторона — CREATE INDEX ... USING hnsw уважает maintenance_work_mem (по умолчанию у Postgres — 64 МБ), и на таблице в миллионы строк с этим лимитом построение индекса займёт часы и будет сбрасывать промежуточные данные на диск.

Не только HNSW: у Flat и IVF своя память

HNSW — не единственный тип индекса, и для памяти это важно: у альтернатив другая арифметика.

Flat, он же полный перебор. Никакого графа — только сырые векторы, память равна первому слагаемому формулы без M × 2 × 4. Поиск линеен по числу точек и дорог по CPU, зато точен на сто процентов и не тратит лишней памяти. Большинство движков переключаются на него автоматически ниже порога — у Qdrant это full_scan_threshold, у пары тысяч записей граф просто не даёт выигрыша, который окупил бы память под него.

IVF, Inverted File Index. Векторное пространство на этапе построения делится k-means’ом на nlist кластеров; в память кроме сырых векторов попадает только таблица центроидов — nlist × размерность × 4 байт, и это немного: nlist обычно берут порядка √N, то есть на миллионе точек — около тысячи центроидов, единицы мегабайт. По памяти IVF почти всегда дешевле HNSW: нет расходов на граф связей на каждую точку. Плата — качество и время: индекс нужно переобучать при заметном дрейфе данных, а recall регулируется параметром nprobe, числом кластеров, которые проверяются при поиске, — рост nprobe возвращает точность и забирает скорость. Тип индекса ivfflat есть у pgvector, IVF_FLAT и IVF_SQ8 — у Milvus.

Практический вывод: если данные почти не меняются и бюджет памяти жёсткий, IVF выигрывает у HNSW по RAM в разы. Если коллекция растёт непрерывно и важен recall, HNSW — дефолт всех пяти движков не просто так.

Ловушки, которые не видны в формуле

Три источника расхождения между расчётом и тем, что покажет free -h.

Перестроение держит старое и новое одновременно. У графовых индексов оптимизация — не правка на месте, а постройка нового сегмента рядом со старым: пока идёт процесс, второй экземпляр графа временно занимает память вдобавок к первому. У Postgres то же самое происходит при CREATE INDEX: пока строится hnsw или ivfflat, maintenance_work_mem расходуется поверх обычной работы базы, и на большой таблице такое построение стоит запускать в окно с низкой нагрузкой.

Диск вместо RAM — это не бесплатно, а по-другому. Когда движок отображает векторы через mmap (Qdrant, Milvus с версии 2.4) вместо загрузки в RAM целиком, docker stats и лимит cgroup могут посчитать заполненным весь объём, хотя фактически это вытесняемый страничный кеш ядра, а не куча процесса. Разница видна по /proc/<pid>/smaps_rollup: поле Anonymous — то, что ядро не может выкинуть, Rss — всё вместе, включая отображённые файлы. Спутать одно с другим — частая причина ложной тревоги «памяти не хватает», когда на деле не хватает NVMe под холодные данные.

Локальная модель эмбеддингов ест отдельно, а не вместо. Если считать эмбеддинги на том же сервере, где живёт база, это второй процесс со своим аппетитом, а не часть бюджета базы. На нашем стенде (AMD EPYC 9554, Ollama 0.33.1) модели в Q4_K_M занимают в памяти: qwen2.5:3b — 2,2 ГБ, mistral:7b — 5,0 ГБ, qwen2.5:7b — 5,1 ГБ, llama3.1:8b — 5,6 ГБ. Эту цифру прибавляют к расчёту базы, а не вычитают из него — иначе на минимальном тарифе первый же батч эмбеддингов утащит с собой и саму базу. Про нехватку памяти в целом — отдельный разбор, что делать при нехватке RAM.

Какой сервер брать в MAATRIX под векторную базу

Порядок расчёта: число точек и размерность → байты на точку по формуле → таблица выше или свой расчёт → плюс payload → плюс входной билет движка из раздела про архитектуру → плюс 30% на пики.

Если движок ещё не выбран, вот честная раскладка. Chroma — для прототипа и коллекций до нескольких сотен тысяч записей, один процесс и минимум настроек. Qdrant — для продакшена с диском в резерве и квантованием, и единственный из пяти движков с готовой сборкой в каталоге apps.maatrix.io: ставится автоматически на Ubuntu и Debian, доступы — в личном кабинете. Если данные уже в Postgres, берите pgvector — отдельный сервис не нужен. Milvus и Weaviate ставятся на чистый сервер по инструкции, не автоматически.

Честный минимум зависит от движка сильнее, чем от коллекции: 2 ГБ у Chroma, 4 ГБ у Qdrant и Weaviate, 8 ГБ у Milvus standalone — это цена входа, а не запас под данные. Практический ориентир по конфигурациям:

СценарийКонфигурацияЧто помещается
Прототип, до 300 тыс. точек2 vCPU, 4 ГБ RAM, 40–60 ГБ NVMeлюбой движок, кроме Milvus
Продакшен, 300 тыс. – 3 млн4 vCPU, 8–16 ГБ RAM, 100–160 ГБ NVMeвсе пять при размерности до 1024
Крупный корпус, от 10 млн8+ vCPU, 32–64 ГБ RAM, выделенный серверс квантованием либо Milvus-кластер

Локация — Великобритания, Лондон. В пайплайне RAG запрос к базе идёт несколько раз за один ответ пользователю, и задержка умножается на каждый переход: из Лондона до дата-центров ЕС — единицы-десятки миллисекунд, а с британского адреса штатно, без региональных ограничений, отвечают API эмбеддингов OpenAI, Cohere и Voyage — тот самый сервис, который считает векторы для загрузки в базу. Плюс соседство с юрисдикцией GDPR, если данные европейские: для большинства RAG-проектов на внешних эмбеддингах Лондон — разумная точка по умолчанию.

Оплата — картой российского банка, по СБП, криптовалютой или токеном MAAT; сервер приходит с чистой Ubuntu 24.04, а какой из пяти движков на него ставить, решает расчёт из этой статьи, а не разница в рекламных обещаниях.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Сколько RAM нужно на миллион векторов?

Зависит от размерности и движка. При 1024 измерениях и float32 — около 4,2 ГБ на векторы и граф, плюс payload и входной билет движка: 2–8 ГБ сверху, от Chroma до Milvus. Практичный ориентир — 8 ГБ для лёгких движков, 16 ГБ для Milvus или payload в памяти.

Какой движок экономнее по памяти?

На один вектор — почти никакой разницы: все пять считают вектор и HNSW-граф одинаково. Разница — во входном билете: Chroma и pgvector (если Postgres уже поднят) дешевле всего на старте, Milvus дороже всех из-за etcd и объектного хранилища рядом, даже на пустой коллекции.

Формула даёт число, а как проверить его на практике?

Загрузите представительную выборку — 20–50 тысяч настоящих векторов — на тестовый сервер и снимите память процесса до и после: grep VmRSS /proc/$(pgrep -x <имя_процесса>)/status. Разница, делённая на число точек, — реальный байт на точку с учётом версии движка и настроек; дальше линейно умножайте на всю коллекцию.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.