MAATRIX / Блог / Сколько RAM нужно для Funkwhale

Сколько RAM нужно для Funkwhale

MAATRIX

Funkwhale часто выбирают как федеративную альтернативу SoundCloud — сервис, где можно не только слушать свою музыку, но и подписываться на чужие библиотеки и каналы по протоколу ActivityPub, как в Mastodon. Проблема в том, что многие подходят к расчёту сервера так же, как для Navidrome или другого лёгкого аудио-плеера, и упираются в нехватку памяти уже на этапе установки. Funkwhale — не один бинарник, а полноценное веб-приложение на Django с PostgreSQL, Redis и очередью фоновых задач Celery, и федерация добавляет постоянную фоновую нагрузку, которой нет у изолированных серверов. Разберём, из чего складывается память Funkwhale и сколько реально закладывать под разные сценарии.

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

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

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

Из чего складывается память Funkwhale

Архитектурно Funkwhale ближе к Nextcloud или Mastodon, чем к Navidrome, — это несколько взаимодействующих процессов, а не один компактный бинарник:

  • API-сервер на Django + Gunicorn. Обрабатывает HTTP-запросы, REST и GraphQL API, аутентификацию. Gunicorn поднимает несколько воркер-процессов (число обычно считают по формуле 2 × ядра + 1), и каждый — отдельный процесс Python с собственным потреблением памяти, обычно от 80 до 150 МБ в покое в зависимости от версии зависимостей.
  • PostgreSQL — обязательная СУБД. В отличие от Navidrome с встроенной SQLite, Funkwhale требует полноценный PostgreSQL-сервер: треки, альбомы, исполнители, подписки, федеративные объекты (Follow, Like, Announce) и очередь активностей хранятся в реляционной базе. Даже небольшой инстанс держит в памяти буферы shared_buffers и кеш планов запросов — фиксированный «налог», которого у SQLite-решений просто нет.
  • Redis — кеш и брокер очередей. Выполняет две роли: кеширует часто запрашиваемые данные (метаданные треков, сессии) и служит брокером сообщений для Celery — через него API ставит фоновые задачи, а воркер их забирает.
  • Celery-воркер — вся тяжёлая и фоновая работа. Импорт библиотеки, генерация превью обложек, обработка входящей и исходящей федерации, уведомления — всё это выполняется асинхронно в отдельном процессе (или нескольких, в зависимости от параметра concurrency). Именно он чаще всего даёт непредсказуемые пики.
  • nginx — обратный прокси и раздача статики. Отдаёт собранный фронтенд (статические файлы Vue.js) и проксирует запросы к API и медиафайлам. Сам по себе лёгкий, но именно через него идёт стриминг аудио.

Сложите базовые состояния этих процессов — и станет понятно, почему Funkwhale в покое ощутимо тяжелее Navidrome даже без единого слушателя: там, где у Navidrome работает один Go-процесс с SQLite, у Funkwhale минимум пять взаимодействующих сервисов, у каждого свой минимальный «вес».

Федерация ActivityPub — постоянный фон, а не разовый пик

Главное архитектурное отличие Funkwhale от локальных медиасерверов — федерация не выключается никогда, пока инстанс на кого-то подписан или на него подписаны. Это меняет саму природу нагрузки: вместо разового пика при сканировании библиотеки появляется ровный фоновый расход, зависящий от активности сети инстансов, а не от действий ваших собственных пользователей.

Что конкретно нагружает Celery-воркер и Redis из-за федерации:

  • Входящие активности. Каждый раз, когда пользователь на другом инстансе лайкает трек, публикует альбом в подписанной вами библиотеке или комментирует — приходит подписанный HTTP-запрос, который нужно проверить (HTTP Signatures), распарсить JSON-LD и сохранить как объект в PostgreSQL.
  • Исходящие активности. Ваши действия (подписки, лайки, публикации) рассылаются подписчикам — при большом числе подписчиков на других инстансах это веерная рассылка HTTP-запросов через Celery.
  • Проксирование удалённого медиа. Обложки альбомов, аватары и иногда сами аудиофайлы с удалённых инстансов кешируются локально через медиапрокси — это не только диск, но и временные всплески памяти при скачивании.
  • Число подписок и подписчиков — главный множитель. Инстанс, подписанный на десяток библиотек, почти не заметит федеративной нагрузки. Инстанс с активным сообществом, подписанный на сотни каналов, держит Celery-воркер в постоянной лёгкой загрузке даже ночью.

Практический вывод: если вы поднимаете Funkwhale только для себя и не собираетесь подписываться на чужие библиотеки (федерацию можно отключить в настройках инстанса), вы фактически убираете самый непредсказуемый источник фоновой нагрузки и получаете профиль памяти, близкий к обычному self-hosted веб-приложению на Django.

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

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

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

Импорт библиотеки и транскодирование

Первая загрузка коллекции у Funkwhale устроена иначе, чем у Navidrome: сканирование не блокирует основной процесс, а ставится в очередь Celery пакетами задач — по одному треку или пачке треков на задачу, в зависимости от версии.

  • Импорт идёт через очередь, а не напрямую. API-процесс при запуске импорта создаёт задачи в Redis, Celery-воркер разбирает их по очереди (или параллельно, если concurrency больше 1), читает теги, извлекает обложки и пишет метаданные в PostgreSQL. Это не блокирует веб-интерфейс, но означает, что при большом импорте воркер держит повышенное потребление памяти долгое время, а не коротким пиком.
  • Транскодирование по требованию. Если клиент запрашивает поток не в исходном формате или битрейте, Funkwhale на лету вызывает внешний процесс ffmpeg. По памяти это сопоставимо с тем же механизмом у Navidrome — обычно несколько десятков мегабайт на активный поток, — но у Funkwhale транскодирование конкурирует за ресурсы с уже занятыми Django, PostgreSQL, Redis и Celery, а не с единственным лёгким бинарником.
  • Параллелизм воркера — прямой рычаг памяти. Параметр concurrency Celery определяет, сколько задач обрабатывается одновременно. Выше параллелизм — быстрее импорт, но и выше пиковое потребление памяти воркера; на серверах с 1–2 ГБ RAM разумно держать его в 1–2, а не задавать по числу ядер.

На практике для библиотеки в несколько тысяч треков полный импорт занимает от получаса до нескольких часов в зависимости от параллелизма и плотности метаданных, и всё это время Celery-воркер работает не в покое — это стоит учитывать при выборе тарифа, если планируете загружать библиотеку сразу целиком.

Сколько RAM закладывать по сценарию использования

Ориентировочные цифры для инстанса на Docker с PostgreSQL, Redis и одним Celery-воркером на Ubuntu 24.04. Это ориентир для выбора тарифа, а не гарантированный потолок — точные значения зависят от версии Funkwhale, числа Gunicorn-воркеров, параллелизма Celery и активности подписанных инстансов.

СценарийRAM в покоеRAM при импорте библиотекиRAM с федерацией и стримингом
Личный инстанс, федерация выключена, 1 пользователь900 МБ – 1,3 ГБ+300–500 МБ
Личный инстанс с федерацией, несколько подписок1,1–1,5 ГБ+300–500 МБ+150–300 МБ фоном
Небольшой инстанс на семью/друзей, 3–10 пользователей1,3–1,8 ГБ+400–700 МБ+300–500 МБ
Инстанс сообщества, активная федерация, десятки подписчиков1,8–2,5 ГБ+500 МБ–1 ГБ+500 МБ–1 ГБ и выше

Нижняя граница почти во всех сценариях уже выше, чем у Navidrome с запасом, — это стоимость обязательной СУБД и очереди задач, а не признак неправильной настройки. Для личного нефедеративного инстанса имеет смысл закладывать сервер с 2 ГБ RAM, для активной федерации и нескольких пользователей — от 4 ГБ, с запасом на пики импорта и на PostgreSQL, которому тоже стоит выделить не менее 256–512 МБ под shared_buffers.

Docker-compose с лимитами памяти

Упрощённая конфигурация с явными лимитами на каждый сервис: без них один процесс при пике (например, воркер во время импорта) может забрать память у PostgreSQL или Redis и уронить весь инстанс целиком.

services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: funkwhale
      POSTGRES_USER: funkwhale
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - "./data/postgres:/var/lib/postgresql/data"
    deploy:
      resources:
        limits:
          memory: 512m

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - "./data/redis:/data"
    deploy:
      resources:
        limits:
          memory: 128m

  api:
    image: funkwhale/api:latest
    restart: unless-stopped
    env_file: .env
    depends_on:
      - postgres
      - redis
    volumes:
      - "./data/music:/music:ro"
      - "./data/media:/app/media"
      - "./data/static:/app/staticfiles"
    deploy:
      resources:
        limits:
          memory: 512m

  celeryworker:
    image: funkwhale/api:latest
    restart: unless-stopped
    command: celery -A funkwhale_api.taskapp worker -l info --concurrency=1
    env_file: .env
    depends_on:
      - postgres
      - redis
    volumes:
      - "./data/music:/music:ro"
      - "./data/media:/app/media"
    deploy:
      resources:
        limits:
          memory: 512m

  nginx:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - "./nginx.conf:/etc/nginx/conf.d/default.conf:ro"
      - "./data/media:/protected/media:ro"
      - "./data/static:/protected/staticfiles:ro"
    depends_on:
      - api
    deploy:
      resources:
        limits:
          memory: 64m

Суммарно лимиты в этом примере дают около 1,7 ГБ жёсткого потолка — под личный инстанс с умеренной федерацией разумно ставить сервер с 2–4 ГБ RAM, чтобы лимиты были ограничителем на случай сбоя, а не постоянным потолком. --concurrency=1 у Celery-воркера намеренно консервативен: поднимать его стоит только если сервер уже показывает запас памяти при обычной нагрузке. Общие принципы работы с лимитами контейнеров разобраны в статье про ресурсы и лимиты CPU и памяти в Docker.

Funkwhale против Navidrome: федерация в обмен на память

Оба сервиса раздают личную музыкальную коллекцию по сети, но по архитектуре и требованиям к серверу это разные весовые категории.

FunkwhaleNavidrome
Федерация с другими серверамиДа, ActivityPubНет
База данныхPostgreSQL (обязательна)Встроенная SQLite
Очередь фоновых задачCelery + RedisНет, всё в одном процессе
Число процессов в поставке5+ (api, worker, postgres, redis, nginx)1 бинарник
Типичный минимум RAM1–1,5 ГБ и выше при федерации512 МБ – 1 ГБ
Возможность подписки на чужие библиотекиДа, основная функцияНет

Разница не в том, что Funkwhale «сделан хуже» — федерация и полноценная СУБД с очередью задач нужны именно для того, чего у Navidrome нет в принципе: подписок на чужие каталоги, лайков и комментариев, общения между независимыми инстансами. Если нужен просто личный стриминг своей коллекции без соцсетевой составляющей, сколько RAM нужно для Navidrome — вопрос с заметно более скромным ответом, а разворачивается сервис по инструкции Navidrome в Docker Compose. Если интересна именно федеративная модель, у Funkwhale похожая логика на другие ActivityPub-проекты вроде PeerTube — с видео-аналогом её можно сравнить по статье PeerTube в Docker Compose, где федерация и очереди задач устроены концептуально так же, только для видео.

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

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

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

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

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

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

Хватит ли 1 ГБ RAM для Funkwhale?

Технически инстанс может запуститься и на 1 ГБ с отключённой федерацией и одним пользователем, но без запаса для импорта библиотеки и любых пиков это рискованно — PostgreSQL, Redis, API и Celery-воркер вместе почти выбирают этот объём уже в состоянии покоя. Комфортный минимум для личного использования — 2 ГБ.

Можно ли заменить PostgreSQL на SQLite, чтобы сэкономить память?

Нет, Funkwhale не поддерживает SQLite как основную СУБД — это архитектурное решение проекта, обусловленное сложностью схемы данных (федеративные объекты, полнотекстовый поиск, права доступа). Экономить на этом компоненте не получится, только закладывать его в расчёт заранее.

Растёт ли память с числом подписанных инстансов и подписчиков?

Да, и это едва ли не главный переменный фактор для Funkwhale — в отличие от локальных медиасерверов, где нагрузка зависит от размера собственной библиотеки, здесь фон создаёт активность целой сети инстансов, на которые вы подписаны или которые подписаны на вас.

Что произойдёт, если памяти не хватит Celery-воркеру во время импорта?

Процесс воркера будет остановлен OOM-killer'ом, задачи, которые он не успел обработать, останутся в очереди Redis и будут подхвачены заново после перезапуска контейнера (restart: unless-stopped) — обычно без потери данных, но с задержкой.

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

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

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