Neo4j: установка на VPS
Если ваши данные — это в первую очередь связи между сущностями (кто с кем дружит, что от чего зависит, кто что купил), реляционная база быстро превращается в лес JOIN-ов и рекурсивных запросов, которые тормозят и плохо читаются. Neo4j хранит данные как узлы и рёбра между ними, поэтому вопросы вроде «покажи всех друзей друзей на глубину 3» решаются одним коротким запросом вместо каскада SQL-костылей. Разворачиваем Neo4j на VPS через Docker за 15 минут: от чистого сервера до первого запроса на Cypher.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое Neo4j и когда она выигрывает у SQL
В реляционной базе данные лежат в таблицах, а связи выражаются через внешние ключи и JOIN. Это отлично работает, пока связей немного и они фиксированной глубины. Проблема начинается, когда нужно пройти по цепочке связей произвольной длины.
Классический пример — социальный граф. Есть таблица users и таблица friendships с парами user_id. Запрос «друзья друзей» — это один JOIN. «Друзья на глубину до 4, исключая уже существующих друзей» — это уже рекурсивный CTE (WITH RECURSIVE), который на каждом уровне глубины умножает объём промежуточных данных и упирается в производительность на графах от нескольких сотен тысяч рёбер. В Neo4j та же задача — это:
MATCH (me:Person {name: 'Анна'})-[:FRIEND*1..4]-(fof:Person)
WHERE NOT (me)-[:FRIEND]-(fof) AND me <> fof
RETURN DISTINCT fof.name
Похожая история с рекомендательными системами («пользователи, купившие X, также купили Y, а те кто купил Y — ещё и Z») и графами зависимостей (пакеты, сервисы в микросервисной архитектуре, детали в BOM-структуре изделия). Везде общий паттерн: обход связей переменной глубины, поиск кратчайшего пути, поиск циклов. В SQL это либо рекурсивные CTE, которые плохо оптимизируются планировщиком, либо денормализация с ручным пересчётом. В Cypher это MATCH с шаблоном пути — база сама умеет эффективно ходить по графу, потому что физически хранит указатель на следующий узел прямо в структуре узла, а не ищет его через индекс каждый раз заново.
Важная оговорка: если у вас классические табличные данные с редкими связями (заказы, склад, биллинг), графовая база не даст выигрыша и добавит только лишнюю систему в инфраструктуру. Neo4j имеет смысл, когда сама суть запросов — это переходы по связям, а не агрегация строк.
Что понадобится
Для установки хватит небольшого VPS: Neo4j Community Edition стартует и на 2 ГБ RAM для тестов, но для рабочей нагрузки с индексами и кэшем страниц комфортнее от 4 ГБ. Понадобятся:
- VPS с Ubuntu 22.04/24.04 (подойдёт и Debian 12);
- установленный Docker и плагин Docker Compose;
- открытые порты 7474 (HTTP, Neo4j Browser) и 7687 (Bolt-протокол для подключений из приложений).
Если Docker ещё не стоит — сначала установите Docker на Ubuntu 24.04, это займёт пару минут. Проверить, что всё готово:
docker --version
docker compose version
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSdocker-compose.yml: поднимаем Neo4j
Создайте рабочую директорию и папки под данные, чтобы они не пропали при пересоздании контейнера:
mkdir -p /opt/neo4j/{data,logs,import,plugins}
cd /opt/neo4j
Файл docker-compose.yml:
services:
neo4j:
image: neo4j:5-community
container_name: neo4j
restart: unless-stopped
ports:
- "7474:7474" # Neo4j Browser (HTTP)
- "7687:7687" # Bolt (подключение из приложений)
volumes:
- ./data:/data
- ./logs:/logs
- ./import:/var/lib/neo4j/import
- ./plugins:/plugins
environment:
- NEO4J_AUTH=neo4j/ВашВременныйПароль123
- NEO4J_server_memory_heap_initial__size=512m
- NEO4J_server_memory_heap_max__size=1G
- NEO4J_server_memory_pagecache_size=512m
ulimits:
nofile:
soft: 40000
hard: 40000
Пара моментов, о которых стоит знать заранее:
NEO4J_AUTH=neo4j/парользадаёт начальный пароль сразу, без ручной смены через браузер — удобно для автоматизации, но пароль всё равно стоит сменить после первого входа, если вы вписали его во временный файл.- Память в примере рассчитана на VPS с 2-4 ГБ RAM. Heap — это память под выполнение запросов, page cache — под кэш данных графа в RAM. Если весь ваш граф с индексами помещается в page cache, чтение будет практически мгновенным; если нет — начнутся обращения к диску на каждый обход.
neo4j:5-community— бесплатная редакция без кластеризации и части enterprise-фич (нет, например, multi-database в полном объёме и role-based security на уровне Enterprise). Для одиночного VPS и большинства проектов её достаточно.
Запуск:
docker compose up -d
docker compose logs -f neo4j
В логах дождитесь строки Started. — обычно это 15-30 секунд на первом старте, потому что база инициализирует структуры на диске.
Первый запуск: Neo4j Browser и смена пароля
Откройте http://IP_вашего_сервера:7474 в браузере. Появится Neo4j Browser — веб-интерфейс для выполнения Cypher-запросов и визуализации графа.
При подключении укажите:
- Connect URL:
bolt://IP_вашего_сервера:7687 - Authentication type: Username / Password
- Username:
neo4j - Password: тот, что задали в
NEO4J_AUTH(илиneo4j, если переменную не задавали — тогда система сразу потребует сменить пароль при первом входе)
Если вы не указывали NEO4J_AUTH в compose-файле, при первом логине с паролем neo4j Neo4j Browser сам покажет форму смены пароля — старый пароль больше не примет ни один клиент, пока вы её не пройдёте. Это встроенная защита от дефолтных учёток, отключить её штатными средствами нельзя, и это правильно.
Если сервер смотрит в интернет напрямую (без VPN и без firewall, ограничивающего доступ к 7474/7687), обязательно смените пароль на длинный и уникальный сразу после первого входа — Neo4j Browser открыт всему интернету, и дефолтные учётки перебирают ботами в первые же часы после старта.
Cypher на практике: первые узлы и связь
Cypher — декларативный язык запросов Neo4j, синтаксически похож на ASCII-рисунок графа: () — узел, [] — связь, -> — направление. Создадим двух людей и связь между ними прямо в консоли Neo4j Browser:
CREATE (a:Person {name: 'Анна', age: 29})
CREATE (o:Person {name: 'Олег', age: 31})
CREATE (a)-[:KNOWS {since: 2021}]->(o)
RETURN a, o
После выполнения Browser нарисует два кружка-узла и стрелку между ними — это и есть визуализация графа, ради которой многие сначала пробуют Neo4j. Теперь найдём созданную связь:
MATCH (a:Person)-[r:KNOWS]->(o:Person)
RETURN a.name, o.name, r.since
Добавим третьего человека и посмотрим на путь между двумя людьми, которые напрямую не связаны:
CREATE (m:Person {name: 'Мария', age: 26})
CREATE (o:Person {name: 'Олег'})-[:KNOWS]->(m)
MATCH p = (a:Person {name: 'Анна'})-[:KNOWS*1..3]-(target:Person {name: 'Мария'})
RETURN p
Это тот самый обход графа переменной глубины (*1..3 — от 1 до 3 связей), о котором шла речь в начале: в SQL такой запрос потребовал бы рекурсивного CTE и явного контроля глубины рекурсии, здесь это одна строка. Для удаления тестовых данных:
MATCH (n:Person) DETACH DELETE n
DETACH DELETE удаляет узел вместе со всеми его связями — без DETACH Neo4j откажется удалять узел, у которого ещё остались рёбра, что спасает от случайного разрыва графа.
Бэкап, доступ снаружи и базовая защита
Данные Neo4j лежат в примонтированной директории /opt/neo4j/data — её и нужно бэкапить. Простой вариант для community-редакции — остановить контейнер и заархивировать данные (Neo4j Community не умеет «горячий» онлайн-бэкап, это фича Enterprise):
docker compose stop neo4j
tar -czf neo4j-backup-$(date +%F).tar.gz -C /opt/neo4j data
docker compose start neo4j
Для боевой базы это означает окно недоступности на время бэкапа — на графах в разумных пределах (до нескольких гигабайт) это секунды-минуты, но если граф крупный, планируйте бэкапы на низкую нагрузку и держите этот момент в голове при выборе Neo4j: сам подход к резервному копированию в бесплатной редакции проще, чем у PostgreSQL с непрерывным WAL-архивированием, но и грубее.
По сети: порт 7474 отдаёт незашифрованный HTTP по умолчанию, и в этом виде выставлять его в открытый интернет не стоит. Разумные варианты — закрыть 7474/7687 в firewall для всех, кроме своего IP или VPN-подсети, либо поставить перед Neo4j реверс-прокси с TLS (например, через nginx или Caddy) и пускать наружу только 443. Для приложений, которые подключаются по Bolt-протоколу из того же дата-центра или через приватную сеть, порт 7687 вообще не обязательно светить наружу — держите его доступным только внутри VPC или через SSH-туннель.
Том data в docker-compose — это то, что нужно перенести при переезде на другой сервер: миграция базы данных между серверами для Neo4j сводится к остановке контейнера, копированию папки data и запуску на новом месте с теми же переменными окружения. Про то, чем volume-подход отличается от bind-mount и когда какой уместнее, — в статье про типы Docker volumes.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Чем Neo4j принципиально отличается от MongoDB, если обе NoSQL?
MongoDB — документная база, оптимизирована под хранение и выборку самодостаточных JSON-подобных документов, связи между документами — это ручная работа приложения. Neo4j хранит связи как часть физической структуры данных и умеет проходить по ним за фиксированное время на каждый шаг, независимо от общего размера графа. Если у вас документы с редкими ссылками друг на друга — берите MongoDB, если суть задачи — обход связей, берите Neo4j.
Можно ли использовать Neo4j вместо PostgreSQL, а не вместе с ним?
Технически можно, но на практике чаще имеет смысл держать их рядом: PostgreSQL — под транзакционные данные (заказы, пользователи, платежи), Neo4j — под конкретный граф-модуль (рекомендации, социальные связи, анализ зависимостей), синхронизируя нужные ID между базами. Полный отказ от реляционной базы ради Neo4j оправдан только если весь домен приложения — это граф.
Сколько памяти реально нужно под Neo4j в проде?
Зависит от размера графа и от того, помещается ли он в page cache. Ориентировочно: для графа на несколько миллионов узлов и рёбер комфортно от 4-8 ГБ RAM, из которых половину стоит отдать под page cache, а не под heap — это ориентир, не измеренная цифра, точный расчёт делается по факту через neo4j-admin server memory-recommendation после наполнения базы реальными данными.
Нужен ли отдельный VPS под Neo4j или хватит общего с другими сервисами?
Для тестов и небольших проектов Neo4j спокойно живёт в одном docker-compose рядом с приложением. Для прода с заметной нагрузкой лучше выделять отдельный сервер или как минимум жёстко ограничивать память контейнера через deploy.resources.limits, чтобы всплеск запросов к графу не забрал память у соседних сервисов.
Как обновить Neo4j на более новую версию?
Смените тег образа в docker-compose.yml (например, neo4j:5-community на конкретную минорную версию), сделайте бэкап папки data, затем docker compose pull && docker compose up -d. Neo4j поддерживает автоматическую миграцию формата хранения между минорными версиями внутри одной мажорной ветки, но перед апгрейдом на новую мажорную версию стоит свериться с release notes — там иногда встречаются breaking changes в Cypher.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →