Что такое микросервисы: разбор для инди-хакеров, солопринеров и вайбкодеров
Микросервисы — это архитектурный паттерн, при котором приложение делится на несколько независимых небольших сервисов, каждый из которых выполняет одну задачу. Но для большинства инди-хакеров и солопринеров микросервисы — это избыточная сложность. Разберём, почему это так и когда всё же стоит думать о декомпозиции.
Микросервисы vs Micro-SaaS: почему путают
Это два совершенно разных понятия, которые часто смешивают из-за приставки «micro»:
- Micro-SaaS — это бизнес-модель: маленький SaaS-продукт для узкой ниши, сделанный одним человеком или маленькой командой
- Микросервисы — это архитектурный паттерн: как организован код внутри приложения
Micro-SaaS почти всегда реализован как монолит. Это оптимально для соло-разработчика.
Что такое микросервисы: аналогия из жизни
Представьте ресторан. Монолит — это ресторан, где один повар делает всё: принимает заказ, готовит, приносит, считает счёт, моет посуду. Медленно, но просто и дёшево.
Микросервисный ресторан: отдельный сотрудник для каждой функции. Один принимает заказы, другой готовит первое, третий — второе, четвёртый подаёт, пятый считает. Быстрее при большом потоке, но требует координации, коммуникации, и один заболевший сотрудник ломает всю цепочку.
Для ресторана с 10 посетителями в день — один повар лучше. Для ресторана с 500 посетителями — нужна специализация.
Как работают микросервисы технически
В монолите функции вызываются напрямую:
# Монолит: вызов функции в памяти
from orders.service import create_order
from payments.service import charge_user
def checkout(user_id, cart):
order = create_order(user_id, cart) # Вызов функции: 0мс, всегда успешно
payment = charge_user(user_id, order.total) # То же самое
return {"order_id": order.id, "status": "confirmed"}
В микросервисах сервисы общаются через сеть:
# Микросервисы: HTTP-запросы между сервисами
import httpx
async def checkout(user_id, cart):
# HTTP-запрос к order-service: может упасть, может timeout
async with httpx.AsyncClient() as client:
order_response = await client.post(
"http://order-service/orders",
json={"user_id": user_id, "cart": cart},
timeout=5.0 # Нужен timeout — иначе зависнем
)
if order_response.status_code != 200:
raise HTTPException(status_code=500, detail="Order service error")
order = order_response.json()
# HTTP-запрос к payment-service
payment_response = await client.post(
"http://payment-service/charge",
json={"user_id": user_id, "amount": order["total"]},
timeout=10.0
)
# А что если payment прошёл, но order потом упал?
# Распределённые транзакции — это отдельная большая проблема
Каждый вызов через сеть добавляет:
- Латентность (1-100мс вместо микросекунд)
- Возможность отказа
- Необходимость обработки ошибок
- Сложность отладки
Компоненты микросервисной архитектуры
API Gateway
Единая точка входа, которая роутит запросы к нужным микросервисам:
# nginx как простой API Gateway
location /api/users/ {
proxy_pass http://user-service:8001/;
}
location /api/orders/ {
proxy_pass http://order-service:8002/;
}
location /api/payments/ {
proxy_pass http://payment-service:8003/;
}
Service Discovery
Микросервисы должны находить друг друга. В Kubernetes это встроено (DNS-имена по имени сервиса). Вне Kubernetes — Consul, Eureka или простой .env с URL-ами.
Message Broker
Для асинхронной коммуникации между сервисами:
# Вместо синхронного HTTP — публикуем событие
import redis
r = redis.Redis()
# Order Service публикует событие
def create_order(user_id, cart):
order = save_to_db(user_id, cart)
# Публикуем событие для других сервисов
r.publish("order_created", json.dumps({
"order_id": order.id,
"user_id": user_id,
"total": order.total
}))
return order
# Payment Service подписан на событие
def listen_for_orders():
pubsub = r.pubsub()
pubsub.subscribe("order_created")
for message in pubsub.listen():
if message["type"] == "message":
order = json.loads(message["data"])
process_payment(order["user_id"], order["total"])
Распределённое логирование
В монолите: tail -f app.log. В микросервисах: нужна централизованная система — ELK Stack, Grafana Loki, Datadog.
Micro-SaaS: бизнес-модель для соло-разработчика
Micro-SaaS — это маленький SaaS-продукт, который:
- Решает одну конкретную проблему в узкой нише
- Приносит $500-$10 000/месяц
- Управляется одним человеком или очень маленькой командой
- Работает без внешних инвестиций
- Монетизируется через подписку
Примеры Micro-SaaS продуктов
- Плагин для Notion/Obsidian с конкретной функцией
- Инструмент для автоматизации работы в конкретном API (Shopify, Stripe, Figma)
- Email-шаблоны для конкретной CRM
- Мониторинг конкретного типа ресурсов
- Автоматическое создание отчётов из Google Analytics
- Конвертер форматов для конкретной индустрии
Как найти идею для Micro-SaaS
- Проблема, с которой вы сами столкнулись в работе
- Боль, о которой жалуются в нишевых форумах/Reddit/Telegram-группах
- Улучшение существующего инструмента для конкретной аудитории
- Автоматизация ручной работы в конкретном workflow
Правило: если вы можете объяснить продукт одним предложением — это хорошо. «Автоматически конвертирует дамп PostgreSQL в CSV и отправляет на email по расписанию» — это Micro-SaaS.
Технический стек для Micro-SaaS в 2026
# Минимальный стек
# FastAPI + SQLite (или PostgreSQL) + Railway.app
from fastapi import FastAPI
from sqlmodel import SQLModel, Field, Session, create_engine
app = FastAPI()
class Subscription(SQLModel, table=True):
id: int = Field(primary_key=True)
email: str
plan: str
active: bool = True
# Деплой: один файл main.py на Railway
# Цена: $5-20/месяц
# Время до первого пользователя: 1 день
Когда Micro-SaaS реально использует микросервисы
Почти никогда на старте. Но есть исключения:
Отдельный AI/ML компонент
# Основное API (FastAPI, монолит)
# + отдельный Python-сервис с ML (требует GPU, heavy dependencies)
# main_api/main.py
async def analyze_text(text: str):
# Отдельный сервис для ML, потому что он тяжёлый
response = await http_client.post(
"http://ml-service/analyze",
json={"text": text}
)
return response.json()
# ml_service/main.py — отдельный деплой на машине с GPU
from transformers import pipeline
analyzer = pipeline("sentiment-analysis")
@app.post("/analyze")
def analyze(request: AnalyzeRequest):
return analyzer(request.text)[0]
Разделение по нагрузке
Если основной API под большой нагрузкой, а тяжёлая обработка файлов (PDF, видео) должна масштабироваться независимо — выделить worker в отдельный сервис.
Типичные паттерны микросервисов
CQRS (Command Query Responsibility Segregation)
Разделение операций чтения и записи на разные сервисы/модели:
# Command: запись через Command Service
class CreateOrderCommand:
user_id: int
items: list[OrderItem]
# Query: чтение через оптимизированные read-модели
class OrdersQuery:
def get_user_orders(self, user_id: int) -> list[OrderSummary]:
# Читаем из отдельной, денормализованной таблицы
# оптимизированной для чтения
...
Saga Pattern: распределённые транзакции
# Проблема: нужно списать деньги И создать заказ атомарно
# Но это разные сервисы с разными БД
# Решение: Saga — цепочка компенсирующих транзакций
class CheckoutSaga:
async def execute(self, user_id, cart):
# Шаг 1: Зарезервировать товары
try:
reservation = await inventory_service.reserve(cart)
except Exception:
# Компенсация не нужна — ничего не сделали
raise
# Шаг 2: Списать деньги
try:
payment = await payment_service.charge(user_id, cart.total)
except Exception:
# Компенсация: освободить резервацию
await inventory_service.release(reservation.id)
raise
# Шаг 3: Создать заказ
try:
order = await order_service.create(user_id, cart, payment.id)
except Exception:
# Компенсация: вернуть деньги и освободить резервацию
await payment_service.refund(payment.id)
await inventory_service.release(reservation.id)
raise
return order
Event-Driven Architecture
Сервисы не вызывают друг друга напрямую, а публикуют события:
# Order Service публикует событие — больше ничего не знает
order_created_event = {
"type": "order.created",
"order_id": order.id,
"user_id": order.user_id,
"total": order.total
}
kafka_producer.send("orders", order_created_event)
# Payment Service подписан на событие — не знает об Order Service
@kafka_consumer("orders", group_id="payment-service")
async def handle_order_created(event):
if event["type"] == "order.created":
await process_payment(event["user_id"], event["total"])
# Email Service тоже подписан
@kafka_consumer("orders", group_id="email-service")
async def handle_order_created(event):
if event["type"] == "order.created":
await send_confirmation_email(event["user_id"])
Инструменты для микросервисов
| Категория | Инструмент | Назначение | |---|---|---| | Оркестрация | Kubernetes, Docker Swarm | Запуск и управление контейнерами | | API Gateway | Kong, Nginx, Traefik | Маршрутизация запросов | | Message Broker | Kafka, RabbitMQ, Redis Pub/Sub | Асинхронная коммуникация | | Service Discovery | Consul, Kubernetes DNS | Поиск сервисов | | Трейсинг | Jaeger, Zipkin, Datadog | Отладка distributed запросов | | Логирование | ELK Stack, Loki, Datadog | Централизованные логи | | Мониторинг | Prometheus + Grafana | Метрики сервисов | | Self-hosted деплой | Coolify, Portainer | Kubernetes-альтернатива |
Путь от монолита к микросервисам
Если вы дошли до точки, когда декомпозиция оправдана:
- Определите «болевой» компонент (тот, что тормозит или часто падает)
- Выделите его в отдельный процесс, но оставьте в том же репозитории (internal microservice)
- Определите API между компонентами (сначала просто функции, потом HTTP)
- Перенесите данные компонента в отдельную таблицу/схему
- Задеплойте компонент как отдельный сервис
- Повторите для следующего «болевого» компонента
Не нужно декомпозировать всё сразу. Strangler Fig Pattern — постепенное «удушение» монолита, компонент за компонентом.
Бэкапы в микросервисной архитектуре
Каждый микросервис имеет свою базу данных — это означает, что бэкапов нужно столько же, сколько сервисов. Это одна из скрытых операционных издержек.
Для монолитного начала используйте dbsend.ru — один инструмент для бэкапов SQLite и PostgreSQL, уходящих в облако. Когда перейдёте к микросервисам — каждую базу нужно бэкапить отдельно.
FAQ
Micro-SaaS и микросервисы — одно и то же? Нет. Micro-SaaS — бизнес-модель (маленький SaaS-продукт). Микросервисы — архитектурный паттерн. Micro-SaaS почти всегда реализован как монолит.
Обязательно ли использовать микросервисы для scalability? Нет. Монолит можно масштабировать горизонтально (несколько инстансов за балансировщиком). WhatsApp обслуживал 900M пользователей с командой из 50 человек, используя Erlang-монолит. Масштабирование — это не причина переходить на микросервисы.
Что такое serverless и как это связано с микросервисами? Serverless (AWS Lambda, Yandex Functions, Cloudflare Workers) — это «функции как сервис». Концептуально похоже на микросервисы, но ещё более атомарно. Платите только за выполнение функции. Подходит для событийной обработки (вебхуки, триггеры), но сложно для stateful приложений.
Docker = микросервисы? Нет. Docker — это контейнеризация. Монолит в Docker-контейнере остаётся монолитом. Docker Compose с несколькими сервисами — это может быть микросервисная архитектура или просто монолит + база данных.
Когда стоит начинать думать о микросервисах? Когда команда выросла до 15+ инженеров, когда разные части системы требуют принципиально разного масштабирования или технологий, или когда деплой одной фичи регулярно ломает что-то в другой части системы. Не раньше.
Каков минимальный размер «микросервиса»? Нет универсального ответа. Принцип: сервис должен делать одну вещь и делать её хорошо. Слишком маленькие сервисы (функция-сервис) создают избыточную операционную нагрузку. Хорошее правило: сервис должен быть управляем одной «пицца-командой» (2-8 человек).