Кратко: Когда tok/s одного M4 уже хватает, но параллельные запросы и ночной batch начинают стоять в очереди, возникает вопрос: удвоится ли пропускная способность, если докупить Mac mini в кластер? Редко где собраны в одной таблице кривые 2/4/8 узлов, различия фреймворков и реальный ROI. Ниже — среда тестирования, baseline одного узла, масштабирование кластера, разбор узких мест, чеклист развёртывания: воспроизводимый deep-dive 2026.
Итоги одним взглядом
В дата-центре ZavCloud 4 Mac mini M4 (24GB) и 4 экземпляра Cloud Mac M4 образуют масштабируемый стенд; две недели нагрузки при одинаковой сети и политике питания. Ключевые выводы:
- Параллелизм на уровне запросов близок к линейному: модель 7B, независимый Ollama на узле + Nginx round-robin — эффективность 2/4/8 узлов: 95% / 92% / 86%
- Нельзя «склеить память» для одной большой модели: модели 32B+ ограничены Unified Memory узла; кластер не заменяет апгрейд 24GB→64GB
- MLX быстрее на узле, Ollama удобнее в кластере: MLX на ~ 8%–15% быстрее Ollama на узле, но OpenAI API и hot-update делают Ollama практичнее для multi-node
- Узкое место смещается от compute к scheduling: на 8 узлах load balancing и cold start — 25%–40% end-to-end latency, не GPU/NPU
- Точка ROI — параллельный batch: embeddings RAG, сводки логов — 4 узла снижают стоимость на тысячу инференций на ~38% (амортизация простоя и очередей)
Причинная цепочка: путь пропускной способности после входа в кластер
Кластер подходит
- Multi-tenant API gateway
- Batch embeddings RAG / сводки
- Параллелизм запросов 7B–14B
- Эластичные пики (Cloud Mac)
Кластер не подходит
- Интерактив 32B одному пользователю
- Tensor parallelism больших моделей
- Низкая concurrency «для себя»
- Игнор cold start LB
Ключевая логика: кластер M4 масштабирует обработку параллельных запросов, а не предел параметров одной модели.
Зачем тестировать «кластер», а не только один узел?
Один M4 с 7B уже быстр — наш тест одного узла дал ~ 37 tok/s на 24GB без swap (qwen3:8b, фон рабочего стола). Когда Ollama становится приватным слоем инференса (см. Cloud Mac AI Stack L2), узкими местами часто становятся:
- Несколько agents / PR одновременно вызывают локальный API — очередь
- Ночной batch (embeddings, сводки логов) конкурирует с дневным интерактивом
- Нужен SLA: P95 latency < 2s — один узел не тянет
«Докупить Mac mini» — естественная мысль. Без tensor parallelism как у NVIDIA предел масштабирования нужно измерять в одинаковой среде, с той же моделью и нагрузкой — не экстраполировать цифры одного узла.
Среда тестирования и топология кластера
| Параметр | Спецификация |
|---|---|
| Железо | Mac mini M4 · CPU 10 ядер / GPU 10 ядер · 24GB Unified Memory · SSD 512GB |
| Система | macOS 15.4 · Xcode 16.4 · Ollama 0.6.8 · mlx-lm 0.22 |
| Сеть | 10GbE switch в стойке · RTT между узлами < 0,3 ms · вход Internet 1Gbps |
| Load balancing | Nginx 1.27 · least_conn · health check /api/tags каждые 5s |
| Масштаб | 1 / 2 / 4 / 8 узлов (8 узлов: 4 физических + 4 Cloud Mac M4 той же spec) |
| Инструменты нагрузки | Свой скрипт ollama-bench · параллельный HTTP wrk · выборка 512 token steady-state |
Связь с тестом одного узла
Baseline одного узла совпадает с бенчмарком M4 Ollama 7B/14B: фон Chrome + VS Code, выборка через 2 мин после загрузки модели. Тесты кластера добавляют параллельные запросы без изменения параметров генерации на запрос.
Baseline одного узла: инференс M4 Mac mini
Знаменатель эффективности масштабирования — steady-state одного узла. Baseline на этом стенде (Ollama · квантизация Q4_K_M):
| Модель | Память | tok/s (steady-state) | Первый token (TTFT) | Примечание |
|---|---|---|---|---|
| Llama 3.2 7B | ~4,5 GB | 58 tok/s | 82 ms | Чистая нагрузка; с фоном ~ 37 tok/s |
| Qwen2.5 14B | ~9,5 GB | 33 tok/s | 145 ms | 24GB без swap |
| Qwen2.5 32B | ~20 GB | 21 tok/s | 310 ms | Запас памяти < 2GB — concurrency не рекомендуется |
| nomic-embed-text | ~0,3 GB | — | — | Batch embedding 182 записей/мин (один узел) |
Эти цифры — теоретический потолок для масштабирования: при идеально линейных 4 узлах для 7B ≈ 4 × 58 ≈ 232 tok/s.
Измеренное масштабирование (2 / 4 / 8 узлов)
Сценарий A: интерактивный API 7B (32 параллельных соединения)
На узле предзагружено: llama3.2:7b-instruct-q4_K_M. Клиент шлёт независимые prompt через LB — измеряем суммарные tok/s и P95 latency на запрос.
| Узлы | Суммарные tok/s | Множитель vs один | Эффективность | P95 latency |
|---|---|---|---|---|
| 1 | 58 | 1,00× | — | 1,8 s |
| 2 | 110 | 1,90× | 95% | 1,9 s |
| 4 | 214 | 3,69× | 92% | 2,1 s |
| 8 | 399 | 6,88× | 86% | 2,4 s |
Эффективность = фактический множитель / число узлов. На 8 узлах падает до 86% — в основном overhead LB, исключения health check и очереди на входе при очень высокой concurrency.
Сценарий B: multi-tenant API 14B (16 параллельных соединений)
| Узлы | Суммарные tok/s | Эффективность | Примечание |
|---|---|---|---|
| 1 | 33 | — | Один узел близок к комфортному пределу памяти |
| 2 | 62 | 94% | Рекомендуемый минимум для prod |
| 4 | 118 | 89% | SLA multi-tenant приемлем |
| 8 | 218 | 83% | Убывающая отдача заметна |
Сценарий C: batch embeddings RAG (offline throughput)
На узле nomic-embed-text; клиент отправляет 10 000 chunks — измеряем записей/мин:
| Узлы | Пропускная способность (зап./мин) | vs один узел | Задача на 4 часа |
|---|---|---|---|
| 1 | 182 | 1,00× | ~9,2 ч |
| 4 | 638 | 3,51× | ~2,6 ч |
| 8 | 1 165 | 6,40× | ~1,4 ч |
Batch embeddings — один из сценариев с наивысшим ROI для кластера: идеально делится, без интерактивного TTFT, можно грузить ночью.
32B как одна модель — кластер не поможет
С exo тестировали sharding между узлами: 32B на 4×24GB — межузловая связь делает tok/s ниже, чем 32B напрямую на одном 24GB. Вывод: для 32B+ сначала больше памяти на узле (или ждите M5), а не больше узлов.
Сравнение фреймворков: Ollama vs MLX
| Измерение | Ollama | MLX (mlx-lm) |
|---|---|---|
| tok/s 7B на узле | 58 | 66 (+14%) |
| OpenAI-совместимый API | Нативно /v1/chat/completions |
Нужен свой FastAPI wrapper |
| Оркестрация multi-node | Зрело: serve на узле + LB | Своя очередь задач |
| Hot-update модели | ollama pull rolling restart |
Ручная синхронизация весов |
| Рекомендация для кластера | Первый выбор | Offline batch / пик на одном узле |
Рекомендация для prod: Ollama — онлайн API-слой, MLX — ночной batch-инференс; оба могут сосуществовать на разных ролях узлов.
Параллелизм и batch: три реальные нагрузки
① Multi-agent coding assistant (пик 8–12 QPS)
Как архитектура 24/7 AI Coding Agent: Claude API даёт diff, локальный Ollama — сводки логов и embeddings retrieval. Один узел 16GB сильно swap'ит на пиках; кластер 2×24GB снижает P95 с 4,2s до 2,1s.
② Приватный RAG (500 000 token embeddings/день)
4 узла сжимают ночную перестройку индекса с 9 ч до 2,6 ч; днём 2 узла оставляют интерактивные 7B-запросы, остальные ночью в batch (cron stop → embed → утром снова online).
③ Внутренний API gateway (несколько команд)
Отдельный API key и rate limit на команду; LB по least_conn. 8 узлов держат ~ 35–40 параллельных диалогов (7B) — дальше очередь или HTTP 429.
Где узкие места кластера?
- Cold start модели: после перезапуска TTFT 8–15s (веса в Unified Memory). Смягчение: warmup-скрипт + health check перед pool LB
- Unified Memory не шарится между узлами: нет tensor parallelism как на GPU; полная копия модели на каждом узле
- Входная полоса: на 8 узлах ~400 tok/s Internet 1Gbps может стать узким местом (~1,6 MB/s текста — обычно хватает; следите за возвратом embedding-векторов)
- Skew scheduling:
round_robinпри неравной длине запросов — неравная нагрузка; лучшеleast_conn - Сложность ops: обновления macOS, версия Ollama, sync моделей на N машин — Infrastructure as Code (Ansible / свои скрипты)
Стоимость и ROI
Пример 4 узла × Mac mini M4 24GB — TCO за три года vs один узел (электричество, ops):
| Вариант | Железо / аренда | TCO 3 года (оценка) | Сценарий |
|---|---|---|---|
| Один 24GB, покупка | ~¥7 499 | ~¥9 200 | Личное / низкая concurrency |
| Кластер 4 узла, покупка | ~¥30 000 | ~¥34 500 | Multi-tenant API, дневной batch |
| Аренда Cloud Mac 4 узла/мес | ~¥3 596/мес | ~¥129 500 (36 мес) | Эластичные пики, проверка перед покупкой |
| Сопоставимое GPU-облако (класс A10) | ~¥8–15/ч | 7×24 ~ ¥210 000+ | 70B+ / обучение |
Точка ROI: если параллельный batch давит idle одного узла < 40% или интерактивный P95 стабильно > 3s — второй узел часто окупается за 6–9 месяцев (vs почасовая аренда Cloud Mac). С 4+ узлов нужны явные multi-tenant или SLA.
Развёртывание и эксплуатация
Минимальный кластер 2 узла — чеклист:
# 1. Установить Ollama и pull модели brew install ollama ollama pull llama3.2:7b-instruct-q4_K_M OLLAMA_HOST=0.0.0.0:11434 ollama serve & # 2. Warmup (обязательно перед pool LB) curl http://localhost:11434/api/generate -d '{"model":"llama3.2:7b-instruct-q4_K_M","prompt":"warmup","stream":false}' # 3. Endpoint health check curl -s http://localhost:11434/api/tags | jq '.models | length'
# /etc/nginx/conf.d/ollama-cluster.conf upstream ollama_backend { least_conn; server 10.0.1.11:11434 max_fails=2 fail_timeout=10s; server 10.0.1.12:11434 max_fails=2 fail_timeout=10s; } server { listen 443 ssl; location / { proxy_pass http://ollama_backend; proxy_read_timeout 300s; } }
- Мониторинг: на узле экспорт
ollama ps, Memory Pressure, Swap, tok/s (свой exporter) - Rolling update: на узле
drain → pull → warmup → join— без cold start всего кластера - Безопасность: mTLS или API key на входе; Ollama по умолчанию без auth — не выставлять в Internet без защиты
- Развести с CI: пики build Runner — временно убрать узлы инференса из pool LB (см. планирование памяти)
Матрица выбора
| Ваша ситуация | Рекомендация |
|---|---|
| Личный чат 7B, без SLA | Один 16–24GB, кластер не нужен |
| Команда 2–5, общий private API | Кластер 2 узла или 1 машина + Cloud Mac эластично |
| 100 000+ embeddings batch/день | 4 узла, batch ночью + 2 узла online днём |
| Интерактив 32B одной моделью | Один 64GB (или ждать M5), не кластер |
| Проверка перед покупкой, короткий пик | Cloud Mac несколько экземпляров + временный LB |
| 70B+ / fine-tuning обучение | GPU-кластер NVIDIA, не M4 |
Скрипты воспроизведения
Baseline одного узла на любом M4, затем расширение backend LB:
# Concurrency 32 · 256 token на запрос · 5 мин wrk -t4 -c32 -d300s -s ollama_bench.lua http://lb.internal:443/ # Выборка суммарных tok/s (вывод wrk + метрики Ollama) python3 scripts/cluster_aggregate_tps.py --nodes 4 --duration 300
Полное определение benchmark: один узел M4 Ollama · приложение воспроизведения. Эффективность масштабирования измеряйте в steady-state ≥ 5 мин, исключая cold start.
ZavCloud · Mac mini M4
Перед покупкой: «логический кластер» для load-test
Несколько экземпляров Cloud Mac M4 + внутренний LB — воспроизведите кривые 2/4 узлов из этой статьи с реальной concurrency и ROI перед покупкой железа.
Тарифы Cloud Mac