Распределённые системы на собеседовании системного аналитика

Зачем SA спрашивают про distributed systems

Современные продукты — это десятки микросервисов, которые общаются по сети. Сеть ненадёжна, сервисы падают, данные могут оказаться неконсистентными. Без понимания этих принципов SA не может проектировать интеграции — он будет рисовать «идеальные» процессы, которые ломаются в production.

На собесе системного аналитика distributed systems — частый блок: либо отдельным раундом, либо в системном кейсе. Уровень: junior — знает CAP; middle — понимает Saga, идемпотентность; senior — спроектирует процесс с учётом partial failures и retry.

CAP-теорема

Consistency, Availability, Partition tolerance. В распределённой системе нельзя обеспечить все три одновременно.

Partition tolerance — обязательна, потому что сети ненадёжны. Сетевой split может произойти всегда.

Реальный выбор: CP vs AP.

  • CP (consistency, partition tolerance): при сетевом split часть системы становится недоступной, чтобы не отдать stale данные. Пример — PostgreSQL в режиме synchronous replication, MongoDB с strong consistency.
  • AP (availability, partition tolerance): при split все ноды доступны, но могут отдать разные данные. Eventual consistency. Пример — Cassandra с QUORUM=1, DynamoDB с eventual reads.

На практике:

  • Банковские транзакции, балансы — CP
  • Социальная сеть (лайки, посты) — AP
  • Кеши, аналитика — AP

Подробнее — CAP-теорема.

ACID

Atomicity, Consistency, Isolation, Durability — гарантии транзакций в БД.

  • Atomicity. Транзакция либо полностью применилась, либо никакой части. Реализуется через write-ahead log.
  • Consistency. Транзакция переводит БД из одного валидного состояния в другое. Соблюдаются constraints (foreign keys, check, unique).
  • Isolation. Параллельные транзакции не мешают друг другу. Уровни: READ UNCOMMITTED → READ COMMITTED → REPEATABLE READ → SERIALIZABLE.
  • Durability. После commit транзакция не теряется даже при падении. WAL → fsync.

Подробнее — ACID и уровни изоляции.

Уровни изоляции и аномалии

Уровень Dirty Read Non-Repeatable Read Phantom Read
READ UNCOMMITTED возможна возможна возможна
READ COMMITTED (default) нет возможна возможна
REPEATABLE READ нет нет возможна
SERIALIZABLE нет нет нет

Dirty read — читаешь незакоммиченные изменения другой транзакции.

Non-repeatable read — второй раз читаешь ту же строку, видишь другое (она была закоммичена изменения).

Phantom read — выполняешь тот же запрос дважды, получаешь разное количество строк (вставлены новые строки).

В Postgres default — READ COMMITTED. Для финансовых операций обычно REPEATABLE READ или SERIALIZABLE.

Distributed transactions

В микросервисах transaction затрагивает несколько сервисов/БД. Как обеспечить атомарность?

2PC (Two-Phase Commit)

Phase 1 (prepare): координатор спрашивает всех участников: «готовы к commit?». Каждый готовит и отвечает yes/no.

Phase 2 (commit/rollback): если все yes — координатор говорит commit, иначе rollback.

Преимущества: strong consistency.

Недостатки: блокирующий (если координатор падает, участники зависают), медленный, плохо масштабируется.

В современных микросервисах редко используется.

Saga

Saga — последовательность локальных транзакций с компенсирующими действиями.

Например, заказ:

  1. Reserve inventory → success
  2. Charge payment → success
  3. Create shipment → fail
  4. Compensate: refund payment, release inventory

Преимущества: не блокирующая, отказоустойчивая, масштабируется.

Недостатки: eventual consistency, сложно тестировать, нужны компенсирующие операции для каждого шага.

Два паттерна реализации Saga:

  • Orchestration. Центральный orchestrator (Camunda, Temporal) управляет процессом.
  • Choreography. Сервисы общаются через events, каждый знает свой шаг.

Подробнее — 2PC vs Saga.

Идемпотентность

Многократный вызов даёт тот же результат. Критично для retry-логики.

Как сделать операцию идемпотентной:

  1. Idempotency-Key. Клиент даёт UUID, сервер дедуплицирует.
  2. Optimistic locking через version. Запрос обновляет если version совпадает.
  3. MERGE/UPSERT вместо INSERT.
  4. State machine — операция переводит ресурс из одного состояния в другое; повторная — no-op.

Пример без идемпотентности (баг):

1. Клиент: POST /payments (списать 1000 руб)
2. Сервер: списал, отвечает 200
3. Сеть упала — клиент не получил ответ
4. Клиент retry: POST /payments
5. Сервер: списал ещё раз → клиент потерял 2000 вместо 1000

С idempotency-key:

1. Клиент: POST /payments + Idempotency-Key: abc123
2. Сервер: списал, сохранил {abc123: result}, отвечает 200
3. Сеть упала
4. Клиент retry: POST /payments + Idempotency-Key: abc123
5. Сервер: нашёл abc123, возвращает прежний result. Не списывает повторно.

Retry и backoff

При failure — повторяем. Но как?

Exponential backoff: задержки 1s → 2s → 4s → 8s → 16s. Снижает нагрузку на падающий сервис.

Jitter: случайный разброс к задержке, чтобы клиенты не штурмовали сервис одновременно после общего падения.

Max retries: обычно 3-5. После — даём пользователю ошибку.

Circuit breaker: если сервис стабильно падает, перестаём вызывать. Открываем circuit, периодически пробуем (half-open).

Bulkhead: изолируем ресурсы (thread pool, connection pool) для разных downstream. Падение одного не вешает остальных.

Подробнее — Bulkhead pattern.

Eventual consistency

В AP-системах данные неконсистентны на короткое время. Что значит для пользователя:

  • Лайк появляется не сразу
  • Баланс может на 100мс показать старое значение
  • Поисковая выдача отражает события с задержкой

Принципы работы с eventual consistency:

  1. Read-your-writes. Юзер видит свои изменения сразу (через sticky session или primary read).
  2. Monotonic reads. Если юзер увидел изменение, не должен в следующем запросе увидеть откат.
  3. Causal consistency. Если событие A произошло до B (юзер опубликовал, потом лайкнул), все наблюдатели видят их в этом порядке.

Типичные вопросы

«CAP — выбрал бы CP или AP для платежной системы?»

CP. Платежи требуют strong consistency. Лучше клиент получит ошибку «попробуйте позже», чем неправильный баланс или дубликат.

«Спроектируй оформление заказа через несколько сервисов»

Saga с orchestrator. Шаги: reserve inventory → charge payment → create shipment → notify customer. Каждый шаг — локальная транзакция, имеет compensation (cancel inventory reservation, refund payment, и т.д.).

«Что делать, если внешний платёжный шлюз timeout?»

(1) Не списываем у клиента баланс сразу. (2) Создаём «pending payment». (3) Опрашиваем шлюз с backoff. (4) Если успех — completed. Если N retry без ответа — манual reconciliation.

«Можно ли использовать 2PC в микросервисах?»

Технически да, через distributed transaction managers. Но не рекомендуется: блокирующий, плохо масштабируется. Saga лучше.

«Что такое split brain?»

При сетевом split две части кластера могут думать, что они leader. Если обе принимают writes — конфликты. Решение: leader election с quorum (Raft, Paxos).

Частые ошибки

  • «У нас всё консистентное». В реальности всё eventual, кроме одного сервиса. SA должен видеть, где консистентность есть, где нет.
  • Игнорировать compensation в Saga. «Откатываем» не работает в распределённой системе; нужны явные compensating actions.
  • Бесконечные retry. Без max и backoff — DoS свой downstream.
  • Идемпотентность как opt-in. Любой write-API должен поддерживать idempotency-key.
  • 2PC «по умолчанию». Это antipattern в современных микросервисах.

FAQ

Что важнее знать — теорию или практику?

Теорию + практический опыт хотя бы с одним подходом. Senior должен спроектировать систему end-to-end с учётом partial failures.

Какие книги?

«Designing Data-Intensive Applications» (Kleppmann) — главная. «Microservices Patterns» (Richardson) — про Saga и микросервисы.

Спрашивают ли Paxos / Raft?

На senior — да, базовое понимание. Не нужно выводить алгоритм, но знать роль leader election.

Чем отличается CAP от PACELC?

PACELC расширяет CAP. При partition (P) выбираем availability или consistency (A/C). Иначе (E) — latency или consistency (L/C). PACELC отвечает на вопрос «какие trade-off-ы в обычной работе».

Сколько готовиться?

С нуля — 2-3 месяца с практикой. Уже работал — 2-4 недели.

Смотрите также