Backend-розробка: Laravel, Node.js, Go, Django, PostgreSQL
На production-серверу о 3:14 ночі черга Laravel Jobs перестала оброблятися. 40 000 необроблених завдань у Redis. Причина: worker упав через memory leak в одному з Jobs (витік через статичну змінну в Eloquent observer), supervisor не перезапустив його через неправильно налаштовану stopwaitsecs. Це не гіпотетичний сценарій — це вівторок.
Backend — це те, що працює коли ніхто не дивиться. Або не працює.
Laravel: від структури проекту до production
Laravel — наш основний фреймворк для бізнес-додатків. Версії 10 та 11, PHP 8.2+.
Що робиться правильно з першого дня
Service Layer поверх Fat Controllers. Controller отримує HTTP-запит, валідує через Form Request, передає дані в Service, повертає відповідь. Бізнес-логіка в Service, не в Controller. Звучить банально, але більшість legacy-проектів — це контролери по 500 рядків з SQL-запитами всередину.
Repository Pattern — обережно. У Laravel його часто переиспользуют. Якщо ви просто оборачиваєте Model::where(...) в метод репозиторія — це бойлерплейт без користі. Repository виправданий коли: потрібно абстрагуватися від джерела даних (БД + кеш + зовнішній API) або коли логіка запитів достатньо складна для ізоляції.
Jobs, Events, Listeners. Все, що можна зробити асинхронно — робимо асинхронно. Відправка email, генерація PDF, синхронізація з зовнішнім API, перерахунок агрегатів — у Queue. Laravel Horizon для моніторингу черг у Redis: видно throughput, failed jobs, час обробки по чергам.
Octane для високої навантаженості. Laravel Octane з RoadRunner або Swoole тримає додаток у пам'яті між запитами — прибирає overhead bootstrap (завантаження конфігів, автозавантаження класів) на кожен HTTP-запит. Прирість: 3–8x на синтетичних бенчмарках, 2–4x на реальних додатках. Важливо: не можна зберігати стан між запитами в статичних змінних — це приводить саме до таких інцидентів, як на початку.
N+1: детектувати, а не лікувати пост-фактум
N+1 — найпоширеніша причина повільних сторінок у Laravel-додатках. Стандартна історія: сторінка працювала нормально в dev із 10 записами, на production з 10 000 — 8-секундна загрузка.
Laravel Debugbar в dev-середовищі показує кількість запитів на сторінку. Більше 20 запитів на одну сторінку — сигнал для аудиту.
preventLazyLoading() в AppServiceProvider (режим розробки):
Model::preventLazyLoading(! app()->isProduction());
Будь-який lazy load викине виключення в dev — це змушує думати про eager loading заздалегідь.
Telescope для профілювання в staging: логує всі запити, jobs, mail, notifications з деталізацією за часом.
PostgreSQL: індекси, які реально потрібні
PostgreSQL 14+ — основна БД на всіх проектах.
Індекси, які часто забувають
Composite indexes для частих WHERE + ORDER BY. Якщо у вас WHERE user_id = ? AND status = ? ORDER BY created_at DESC — потрібен (user_id, status, created_at DESC). Індекс за (user_id) окремо погано допомагає з сортуванням.
Partial indexes. Якщо 95% запитів йде з WHERE status = 'active':
CREATE INDEX idx_orders_active ON orders (created_at DESC)
WHERE status = 'active';
Індекс маленький, швидкий, охоплює основне навантаження.
GIN-индексы для JSONB та масивів. Зберігаєш метадані в JSONB? Оператор @> без GIN-індексу — seq scan. З індексом — швидко навіть на мільйонах записів.
GIN для full-text search. to_tsvector + GIN замість LIKE '%query%'. LIKE без індексу — завжди seq scan. З розширенням pg_trgm та gin_trgm_ops — підтримка LIKE з індексом, корисно для CRM-пошуку за частковим збігом.
Connection pooling
Rails, Laravel, Django відкривають нове з'єднання з PostgreSQL на кожен PHP/Python процес. На 100 workers — 100 з'єднань. PostgreSQL починає деградувати від 200–300 активних з'єднань — overhead на управління з'єднаннями стає значним.
PgBouncer — connection pooler перед PostgreSQL. Режим transaction pooling: з'єднання з PostgreSQL зайняте тільки на час транзакції, між запитами повертається в пул. 1000 app workers → 20–50 реальних з'єднань до PostgreSQL.
Node.js з Fastify: коли це краще ніж Laravel
Node.js виправданий для:
- Realtime: WebSocket-сервери, Server-Sent Events, чат, live-оновлення
- Streaming: великі файли, відео, дані потоком
- High I/O concurrency: багато паралельних запитів до зовнішніх API без важкої бізнес-логіки
- Serverless: Lambda/Cloud Functions — Node.js стартує швидше
Fastify замість Express: у 2–3 рази швидше на benchmarks, вбудована JSON Schema валідація, краща TypeScript підтримка, plugin-архітектура.
Типова архітектура realtime: Laravel — основна бізнес-логіка та REST API. Node.js + Socket.io або ws — WebSocket сервер. Laravel публікує події в Redis Pub/Sub, Node.js підписується та транслює клієнтам. Це розділення дозволяє масштабувати WebSocket-сервер незалежно від основного додатку.
Go: мікросервіси та висока навантаженість
Go використовуємо для:
- Високонавантажених мікросервісів (> 10 000 RPS)
- Фонових workers із жорсткими вимогами до latency
- DevOps інструментів та CLI
- gRPC-сервісів у мікросервісній архітектурі
Goroutines — в тисячи разів дешевші ніж OS-потоки. 10 000 конкурентних з'єднань на Go — норма на одному серверу.
Але Go — це не магічна таблетка. Розробка повільніша ніж на Laravel: більше бойлерплейту, немає ORM рівня Eloquent, обробка помилок через if err != nil везде. Виправданий тільки коли продуктивність — реальна вимога, не припущення.
Django та Python backend
Django з DRF (Django REST Framework) — для завдань де потрібен Python: ML-пайплайни, обробка даних, інтеграції з AI-інструментами.
Celery для фонових завдань — аналог Laravel Queue, але складніший у конфігурації. Celery Beat для cron-завдань.
Django ORM проти raw SQL: ORM зручний для CRUD. Для аналітичних запитів із кількома JOIN, оконними функціями та CTE — connection.execute() з raw SQL читабельніший та передбачуваніший.
Redis: більше ніж кеш
Redis у наших проектах виконує кілька ролей:
| Роль | Деталі |
|---|---|
| Кеш | Кешування результатів важких запитів, HTML фрагментів |
| Черги | Backend для Laravel Queue / Celery |
| Session store | Розподілені сесії в multi-instance середовищі |
| Pub/Sub | Realtime події між сервісами |
| Rate limiting | Sliding window counters для API throttling |
| Leaderboards | Sorted Sets для рейтингів |
Redis Cluster для горизонтального масштабування. Sentinel для автоматичного failover на standalone установках.
Розгортання та інфраструктура
Docker + docker-compose — стандарт для локальної розробки та production. Кожен сервіс у контейнері: PHP-FPM/Octane, Nginx, PostgreSQL, Redis, Queue Worker, Scheduler.
CI/CD через GitHub Actions:
- Прогон тестів (PHPUnit / Pest, Vitest, Playwright)
- Збірка Docker-образу
- Push у Container Registry
- Deploy:
docker pull→docker-compose up -dна серверу, або Kubernetes rolling update
Zero-downtime deploy для Laravel: php artisan down --secret=TOKEN не потрібен при правильній установці. Стратегія: новий контейнер стартує поруч зі старим, Nginx перемикає трафік після health check, старий контейнер зупиняється.
Моніторинг: Sentry для exception tracking з alerting в Slack/Telegram. Grafana + Prometheus (або Grafana Cloud) для метрик: CPU, memory, request rate, queue depth, database connection count. Алерт на: error rate > 1%, p99 latency > 2s, queue depth > 1000 jobs.
Орієнтири за термінами
| Завдання | Термін |
|---|---|
| REST API для мобільного/SPA (середня складність) | 6–12 тижнів |
| Backend зі складною бізнес-логікою + інтеграції | 12–20 тижнів |
| Високонавантажений сервіс на Go | 8–16 тижнів |
| Міграція legacy PHP на Laravel | 16–32 тижні |
Вартість розраховується індивідуально після аналізу вимог до навантаження, інтеграцій та бізнес-логіки.







