Сколько RAM нужно для векторной базы: расчёт
«Сколько нужно RAM» для векторной базы обычно узнают постфактум: контейнер уходит с кодом 137 на первой крупной заливке, а на форуме отвечают «у нас взлетело на 8 ГБ», не называя ни размерность вектора, ни движок. Память под векторный индекс считается заранее и без бенчмарков — у неё простая арифметика, почти одинаковая для Qdrant, Milvus, Weaviate, Chroma и pgvector. Разберём формулу по частям, сравним, во что упирается каждый движок ещё до первой точки, и посчитаем, сколько векторов поместится в 4, 8, 16, 32 и 64 ГБ.
Содержание
- Почему «сервер с запасом» не работает
- Универсальная формула: сколько памяти нужно на один вектор
- Таблица: сколько векторов поместится в 4, 8, 16, 32 и 64 ГБ памяти
- Не только векторы: во что упирается конкретный движок ещё до первой точки
- Не только HNSW: у Flat и IVF своя память
- Ловушки, которые не видны в формуле
- Какой сервер брать в MAATRIX под векторную базу
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество 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 измерения |
|---|---|---|
float32 | 4 | 4096 байт |
float16 / bfloat16 | 2 | 2048 байт |
int8 (скалярное квантование) | 1 | 1024 байта |
| binary | 1/8 | 128 байт |
Граф HNSW. На нулевом слое у точки до M × 2 связей, каждая хранится как 4-байтный идентификатор соседа: M × 2 × 4 байт на точку, верхние слои добавляют единицы процентов сверху. У Qdrant и Milvus параметр называется m и по умолчанию равен 16, что даёт 128 байт графа на точку; у pgvector то же имя и то же значение по умолчанию с версии 0.5.0, когда в него добавили HNSW. Конструкция графа у остальных движков идентична, но дефолт может отличаться — сверяйтесь с документацией своего движка перед расчётом, а не берите чужой множитель.
Итоговая формула на точку:
байт_на_точку ≈ размерность × байт_на_координату + M × 2 × 4
Пример: 1 миллион точек, размерность 1024, float32, M = 16 — 1024 × 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 — запас на пики при перестроении и рост коллекции, — и делим на байты на точку по формуле выше.
| RAM | 384 измерения | 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 и mmap | int8, product, binary |
| Weaviate | один процесс (Go) | 4 ГБ RAM | ограниченно | PQ, BQ |
| Milvus standalone | 3 контейнера: сервис, 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 — десятки моделей в одном окне. Оплата картой РФ и по СБП.