Sync/async communication, message brokers | Quizlet

0.0(0)
Studied by 0 people
call kaiCall Kai
learnLearn
examPractice Test
spaced repetitionSpaced Repetition
heart puzzleMatch
flashcardsFlashcards
GameKnowt Play
Card Sorting

1/34

encourage image

There's no tags or description

Looks like no tags are added yet.

Last updated 4:24 PM on 6/19/26
Name
Mastery
Learn
Test
Matching
Spaced
Call with Kai

No analytics yet

Send a link to your students to track their progress

35 Terms

1
New cards

Что такое синхронная и асинхронная коммуникация между сервисами? В чем ключевое отличие?

Синхронная коммуникация (request-response) — как домашний телефон:

- Вызывающий знает о вызываемом

- Вызываемый не знает кто ему звонит

- Формат коммуникации определяет вызываемый (он первичен)

- Вызывающий ждет ответа и блокируется

Асинхронная коммуникация (producer-consumer) — как радио:

- Паблишер транслирует, не зная кто слушает

- Слушатель знает про источник вещания

- Формат определяет паблишер

- Паблишер не ждет реакции слушателей

Ключевое отличие: блокирующий vs неблокирующий характер взаимодействия.

Примеры:

- Синхронная: REST API вызов с ожиданием ответа

- Асинхронная: отправка сообщения в очередь RabbitMQ

Частая ошибка: Путать протокол (HTTP) со стилем взаимодействия (синхронный/асинхронный)

2
New cards

Какие преимущества и недостатки у синхронной коммуникации?

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

- Простота реализации и понимания flow

- Немедленный результат операции

- Легче отлаживать и тестировать

- Привычная модель программирования

- Проще обработка ошибок

Недостатки:

- Сильная связанность сервисов (tight coupling)

- Блокировка потока на время ожидания

- Каскадные отказы при недоступности сервиса

- Сложность масштабирования

- Увеличение общей латентности при цепочке вызовов

Пример проблемы: Если сервис B недоступен, сервис A тоже перестает отвечать клиентам

3
New cards

Какие преимущества и недостатки у асинхронной коммуникации?

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

- Слабая связанность сервисов (loose coupling)

- Отказоустойчивость — сообщения буферизуются в брокере

- Лучшая масштабируемость

- Возможность обработки пиковых нагрузок

- Параллельная обработка задач

Недостатки:

- Сложность реализации и отладки

- Нет немедленного результата

- Сложнее обработка ошибок

- Необходима дополнительная инфраструктура (брокер)

- Возможны проблемы с порядком сообщений

- Eventually consistency вместо strong consistency

Частая ошибка: Использовать асинхронность везде, даже где нужен немедленный ответ

4
New cards

Всегда ли HTTP — это синхронная коммуникация? Приведи примеры асинхронного использования HTTP.

Нет, HTTP может использоваться асинхронно.

Примеры асинхронного HTTP:

1. Webhooks — сервис A регистрирует callback URL, сервис B вызывает его когда готов результат

2. Long polling — клиент держит соединение открытым, сервер отвечает когда появятся данные

3. Server-Sent Events (SSE) — сервер пушит события клиенту

4. HTTP/2 Server Push

5. Паттерн "202 Accepted" — сервер принимает запрос и возвращает ID задачи, клиент потом проверяет статус

Пример webhook:

- GitHub отправляет HTTP POST на твой URL при push в репозиторий

- Твой сервис обрабатывает событие асинхронно

Частая ошибка: Думать, что протокол определяет синхронность (на самом деле это паттерн использования)

5
New cards

Всегда ли брокеры сообщений — это асинхронная коммуникация?

В подавляющем большинстве случаев да, но можно реализовать синхронный паттерн.

Синхронный паттерн через брокер (Request-Reply):

1. Клиент отправляет сообщение с correlation ID

2. Клиент блокируется и ждет ответ в отдельной очереди

3. Сервер обрабатывает и отправляет ответ с тем же correlation ID

4. Клиент получает ответ и продолжает работу

Почему так делают редко:

- Теряются преимущества асинхронности

- Усложнение без выигрыша

- Есть более подходящие инструменты (gRPC, REST)

Частая ошибка: Реализовывать RPC через брокер без веской причины

Практическое правило: Используй брокеры для fire-and-forget или когда ответ может прийти сильно позже

6
New cards

Как повысить отказоустойчивость при HTTP-взаимодействии между сервисами?

Основные подходы:

1. Retry с exponential backoff

- Повторять запросы с увеличивающейся задержкой

- Например: 1с, 2с, 4с, 8с

2. Circuit Breaker

- Прекращать попытки при множественных отказах

- Переход в состояния: Closed -> Open -> Half-Open

3. Timeout на запросы

- Не ждать ответа бесконечно

- Fail fast принцип

4. Bulkhead (изоляция ресурсов)

- Отдельные пулы потоков для разных сервисов

- Проблема одного сервиса не блокирует остальные

5. Fallback механизмы

- Кэш последних успешных ответов

- Дефолтные значения

- Деградация функциональности

6. Health checks и load balancing

- Не отправлять запросы на нездоровые инстансы

Инструменты в .NET: Polly, HttpClientFactory с Polly

7
New cards

Что проще писать и поддерживать: синхронное или асинхронное взаимодействие? Почему?

Синхронное взаимодействие проще писать и поддерживать.

Почему синхронное проще:

- Линейный flow выполнения

- Привычная модель try-catch для ошибок

- Легче отлаживать (stack trace сохраняется)

- Меньше moving parts

- Проще тестировать

- Нет проблем с eventual consistency

Сложности асинхронного:

- Распределенные транзакции

- Обработка дубликатов

- Компенсирующие действия при ошибках

- Мониторинг и трассировка

- Дебаг через несколько сервисов

- Race conditions

Когда асинхронное оправдано:

- Долгие операции (генерация отчетов)

- Интеграция с внешними системами

- Обработка пиковых нагрузок

- Fire-and-forget сценарии

Правило: Начинай с синхронного, переходи на асинхронное при необходимости

8
New cards

Зачем вообще использовать брокеры сообщений? Какие задачи они решают? Как брокер может использоваться для асинхронной обработки внутри одного сервиса?

Основные задачи брокеров:

1. Развязка (decoupling) сервисов

- Producer не знает о consumer

- Можно добавлять/удалять консьюмеров

2. Буферизация и сглаживание нагрузки

- Брокеры супер эффективно проглатывают большой поток сообщений

- Consumer обрабатывает в своем темпе

- Защита от пиковых нагрузок

3. Надежная доставка

- Сообщения не теряются при сбоях

- Retry механизмы

Паттерн "публикация для себя":

- API endpoint быстро принимает запрос

- Публикует задачу в очередь

- Возвращает клиенту request_id

- Фоновый воркер обрабатывает в своем темпе

- Клиент поллит статус по request_id

Пример:

1. POST /reports/generate -> возвращает {id: "abc-123", status: "pending"}

2. Задача в очереди на генерацию

3. GET /reports/abc-123/status -> {status: "processing"}

4. GET /reports/abc-123/status -> {status: "completed", url: "..."}

Выгоды:

- Быстрый отклик пользователю

- Защита от таймаутов на долгих операциях

- Масштабирование воркеров независимо от API

9
New cards

Что такое push и pull модель в контексте консьюмеров? Какая модель лучше и когда?

Push модель (RabbitMQ):

- Брокер активно отправляет сообщения консьюмеру

- Консьюмер регистрирует callback

- Брокер контролирует скорость доставки

Pull модель (Kafka):

- Консьюмер сам запрашивает сообщения

- Консьюмер контролирует скорость обработки

- Polling цикл

Когда Push лучше:

- Низкая латентность важна

- Простые сценарии обработки

- Мало консьюмеров

- Равномерная нагрузка

Когда Pull лучше:

- Консьюмеры с разной производительностью

- Batch обработка

- Нужен контроль над скоростью

- Replay сообщений

Гибридный подход:

- Push с prefetch limit (RabbitMQ)

- Long polling (компромисс)

Частая ошибка: Не учитывать производительность консьюмера при выборе модели

10
New cards

Что такое Exchange в RabbitMQ? Какие типы существуют (fanout, topic, direct, headers) и когда какой использовать?

Exchange — точка входа сообщений в RabbitMQ, роутер который направляет сообщения в очереди по правилам.

Типы Exchange:

1. Direct

- Точное совпадение routing key

- Использование: роутинг по типу сообщения

- Пример: "order.created" -> очередь обработки заказов

2. Fanout

- Broadcast всем привязанным очередям

- Игнорирует routing key

- Использование: уведомления всем подписчикам

- Пример: обновление кэша на всех серверах

3. Topic

- Паттерн matching с wildcards (* и #)

- * — одно слово, # — ноль или более слов

- Использование: гибкая подписка на события

- Пример: "order.*" подпишется на "order.created" и "order.updated"

4. Headers

- Маршрутизация по заголовкам сообщения

- Редко используется

- Использование: сложная логика роутинга

Частая ошибка: Использовать fanout когда нужен topic (теряется гибкость)

11
New cards

Что такое Queue в RabbitMQ и как она связана с Exchange?

Queue — буфер, который хранит сообщения до обработки консьюмером.

Связь с Exchange:

1. Exchange не хранит сообщения, только маршрутизирует

2. Queue привязывается к Exchange через binding

3. Binding содержит routing key или паттерн

4. Одна Queue может быть привязана к нескольким Exchange

5. Один Exchange может маршрутизировать в несколько Queue

Свойства Queue:

- Durable — переживет ли рестарт сервера

- Exclusive — только для одного соединения

- Auto-delete — удалится когда отключатся все консьюмеры

- TTL — время жизни сообщений

- Max length — максимальное количество сообщений

Пример flow:

Producer -> Exchange (routing) -> Binding (фильтр) -> Queue (хранение) -> Consumer

Частая ошибка: Путать persistent сообщения и durable очереди (нужно и то, и другое для надежности)

12
New cards

Что такое routing key и binding в RabbitMQ?

Routing key — метка на сообщении, которую producer устанавливает при отправке. Строка, разделенная точками (например, "order.created.eu").

Binding — связь между Exchange и Queue с правилами маршрутизации.

Как работает:

1. Producer отправляет сообщение с routing key

2. Exchange смотрит на bindings

3. Сравнивает routing key с правилами binding

4. Направляет в подходящие очереди

Примеры для разных Exchange:

- Direct: точное совпадение

- Routing key: "order.created"

- Binding key: "order.created" — совпадение

- Topic: паттерны

- Routing key: "order.created.eu"

- Binding key: "order.*.eu" — совпадение

- Binding key: "order.#" — совпадение

- Fanout: игнорирует routing key

Практический пример:

- Сервис логирования подписан на "*.error"

- Сервис аудита подписан на "order.#"

- Сервис нотификаций подписан на "order.created"

13
New cards

Опиши путь сообщения от паблишера до консьюмера в RabbitMQ. Где настраиваются правила маршрутизации — на Queue или на Exchange?

Путь сообщения:

1. Publisher создает сообщение с routing key

2. Publisher отправляет в конкретный Exchange

3. Exchange получает сообщение

4. Exchange проверяет все bindings

5. По правилам binding определяет целевые Queue

6. Сообщение копируется в каждую подходящую Queue

7. Consumer читает из своей Queue

8. Consumer отправляет acknowledgment

9. Queue удаляет сообщение

Правила маршрутизации:

- Тип маршрутизации настраивается на Exchange (direct/topic/fanout/headers)

- Конкретные правила настраиваются в Binding

- Queue сама по себе правил не содержит

Важные моменты:

- Если нет подходящих bindings — сообщение теряется

- Exchange не хранит сообщения

- Одно сообщение может попасть в несколько Queue

Частая ошибка: Думать что routing настраивается на Queue (на самом деле в binding между Exchange и Queue)

14
New cards

Что такое Dead Letter Queue в RabbitMQ? Когда и зачем используется?

Dead Letter Queue (DLQ) — специальная очередь для сообщений, которые не удалось обработать.

Когда сообщение попадает в DLQ:

1. Превышен TTL сообщения

2. Очередь переполнена (max-length)

3. Сообщение отклонено с requeue=false

4. Превышено количество попыток доставки

Настройка:

- На основной очереди указывается x-dead-letter-exchange

- Опционально x-dead-letter-routing-key

- Создается отдельная очередь для dead letters

Зачем нужна:

- Не терять проблемные сообщения

- Анализ ошибок

- Ручная обработка или retry

- Алертинг о проблемах

Пример использования:

1. Обработка платежа failed 3 раза

2. Сообщение попадает в DLQ

3. Алерт команде support

4. Ручной разбор и исправление

5. Переотправка в основную очередь

Частая ошибка: Не мониторить DLQ (сообщения накапливаются)

15
New cards

Как работает механизм acknowledgement в RabbitMQ? Что происходит с сообщением при ошибке обработки?

Acknowledgement (ack) — подтверждение от консьюмера что сообщение успешно обработано.

Режимы:

1. Automatic ack — сразу при доставке консьюмеру

2. Manual ack — консьюмер явно подтверждает

При manual ack есть варианты:

- basic.ack — успешно обработано, удалить из очереди

- basic.nack — ошибка обработки

- basic.reject — отклонить одно сообщение

При ошибке (nack/reject):

- requeue=true — вернуть в очередь, попробует другой консьюмер

- requeue=false — удалить или отправить в DLQ

Что происходит при сбое консьюмера:

1. Соединение разрывается

2. Все неподтвержденные сообщения возвращаются в очередь

3. Становятся доступны другим консьюмерам

Best practices:

- Ack только после полной обработки

- Использовать prefetch для контроля количества

- Настроить DLQ для проблемных сообщений

- Идемпотентность для повторных обработок

Частая ошибка: Ack до завершения обработки (потеря при сбое)

16
New cards

Что произойдет с сообщением, если в Exchange типа direct отправить сообщение с routing key, для которого нет binding?

Сообщение будет потеряно (dropped silently).

Почему:

- Exchange не хранит сообщения

- Нет подходящего binding = некуда направить

- RabbitMQ не возвращает ошибку по умолчанию

Как узнать о потере:

1. Mandatory flag при публикации

- Вернет basic.return если не нашел queue

- Publisher должен обработать return

2. Alternate Exchange

- Запасной exchange для unrouted сообщений

- Настраивается как параметр основного exchange

Пример защиты от потери:

```

// Настройка alternate exchange

declare exchange "main" with alternate-exchange="unrouted"

declare fanout exchange "unrouted"

declare queue "unrouted-messages"

bind "unrouted-messages" to "unrouted"

```

Best practice:

- Всегда настраивай alternate exchange для critical сообщений

- Мониторь unrouted очередь

- Используй mandatory=true в development

Частая ошибка: Не проверять наличие bindings перед отправкой важных сообщений

17
New cards

Что такое prefetch count в RabbitMQ и зачем его настраивать?

Prefetch count (QoS) — количество сообщений, которые RabbitMQ отправит консьюмеру до получения acknowledgment.

Как работает:

- prefetch=1: консьюмер получит новое сообщение только после ack предыдущего

- prefetch=10: консьюмер может иметь до 10 неподтвержденных сообщений

- prefetch=0: без ограничений (по умолчанию)

Зачем настраивать:

1. Равномерное распределение нагрузки

- Без prefetch быстрый консьюмер заберет все

- С prefetch=1 каждый берет по одному

2. Защита от перегрузки

- Консьюмер не захлебнется сообщениями

- Контроль памяти

3. Оптимизация производительности

- Баланс между throughput и latency

- Уменьшение сетевых round trips

Как выбрать значение:

- CPU-intensive задачи: prefetch=1-2

- I/O задачи: prefetch=10-50

- Быстрые задачи: prefetch=100+

Частая ошибка: Оставлять prefetch=0 и удивляться неравномерной нагрузке между консьюмерами

18
New cards

Что такое Topic в Kafka?

Topic — логическая категория или канал, в который публикуются сообщения. Аналог "темы" в pub/sub системах.

Ключевые характеристики:

- Именованный поток записей

- Разделен на партиции

- Хранит все сообщения в течение retention периода

- Многократное чтение (в отличие от очередей)

Структура:

- Topic состоит из одной или более партиций

- Каждая партиция — упорядоченный лог

- Сообщения имеют offset внутри партиции

Настройки Topic:

- Количество партиций

- Replication factor

- Retention (по времени или размеру)

- Compression

- Cleanup policy (delete/compact)

Примеры топиков:

- user-events

- order-transactions

- application-logs

- inventory-updates

Отличие от RabbitMQ Queue:

- Kafka сохраняет сообщения после чтения

- Несколько consumer groups могут читать независимо

- Можно перечитать с любого offset

19
New cards

Что такое Partition в Kafka? Как Partition Key влияет на распределение сообщений по партициям?

Partition — упорядоченная последовательность сообщений внутри топика. Единица параллелизма в Kafka.

Зачем нужны партиции:

- Масштабирование (больше партиций = больше параллелизма)

- Распределение нагрузки между брокерами

- Упорядоченность внутри партиции

Partition Key:

- Опциональный ключ при отправке сообщения

- Определяет в какую партицию попадет сообщение

- Хэш от ключа определяет номер партиции

Распределение сообщений:

1. С ключом: hash(key) % число_партиций

- Одинаковый ключ = та же партиция

- Гарантия порядка для одного ключа

2. Без ключа: round-robin или random

- Равномерное распределение

- Нет гарантии порядка

Примеры использования ключей:

- userId — все события пользователя в одной партиции

- orderId — порядок событий заказа

- customerId — история клиента

Важно: Изменение числа партиций ломает распределение существующих ключей!

Частая ошибка: Неравномерное распределение ключей (hot partition)

20
New cards

Что такое Offset в Kafka?

Offset — уникальный последовательный идентификатор сообщения внутри партиции. Начинается с 0.

Характеристики:

- Монотонно возрастает

- Уникален в пределах партиции

- Неизменяем

- Присваивается при записи

Использование offset:

1. Consumer tracking

- Каждый consumer group хранит свой offset

- Показывает где остановились в чтении

2. Replay сообщений

- Можно сбросить offset назад

- Перечитать с любой точки

3. Exactly-once семантика

- Commit offset только после обработки

Виды offset:

- Log end offset — последнее сообщение в партиции

- Current offset — где сейчас читает consumer

- Committed offset — последний сохраненный offset

Хранение offset:

- Старые версии: Zookeeper

- Новые версии: internal topic __consumer_offsets

Пример: Partition 0: [0,1,2,3,4,5...100]

- Consumer A на offset 50

- Consumer B на offset 90

21
New cards

Что такое Consumer и Consumer Group в Kafka?

Consumer — приложение, которое читает сообщения из топиков.

Consumer Group — логическая группа консьюмеров, работающих вместе для обработки топика.

Ключевые правила Consumer Group:

1. Каждая партиция читается только одним консьюмером в группе

2. Один консьюмер может читать несколько партиций

3. Разные группы читают независимо

Распределение партиций:

- 4 партиции, 2 консьюмера: каждый читает по 2

- 4 партиции, 4 консьюмера: каждый читает по 1

- 4 партиции, 6 консьюмеров: 2 консьюмера idle

Зачем нужны группы:

- Масштабирование обработки

- Отказоустойчивость (rebalancing при сбое)

- Независимое чтение разными приложениями

Примеры:

- analytics-service (группа 1) — для аналитики

- billing-service (группа 2) — для биллинга

- Обе читают один топик orders независимо

Rebalancing:

- При добавлении/удалении консьюмера

- Перераспределение партиций

- Короткая недоступность

22
New cards

Опиши путь сообщения от паблишера до консьюмера в Kafka.

Путь сообщения:

1. Producer:

- Создает ProducerRecord (topic, partition?, key?, value)

- Сериализует ключ и значение

- Если partition не указан — выбирает по ключу или round-robin

2. Batching:

- Producer накапливает сообщения в batch

- Отправляет batch при достижении размера или timeout

3. Broker (Leader):

- Получает batch

- Записывает в лог партиции

- Присваивает offset каждому сообщению

- Ждет подтверждения от replicas (если acks>1)

- Отправляет ack producer'у

4. Replication:

- Follower replicas копируют данные от leader

- In-Sync Replicas подтверждают получение

5. Consumer:

- Pull запрос к leader партиции

- Указывает offset откуда читать

- Получает batch сообщений

- Обрабатывает сообщения

- Commit offset (автоматически или вручную)

Важные моменты:

- Только leader принимает запись

- Consumer всегда читает от leader

- Zero-copy оптимизация при чтении

23
New cards

Когда использовать RabbitMQ, а когда Kafka? Назови ключевые критерии выбора и архитектурные отличия.

Используй RabbitMQ когда:

- Сложная маршрутизация (topic exchanges)

- Нужны традиционные очереди с удалением после чтения

- RPC паттерны

- Приоритеты сообщений

- TTL для сообщений

- Небольшой/средний объем данных

Используй Kafka когда:

- Высокий throughput (миллионы сообщений/сек)

- Event sourcing / лог событий

- Нужно перечитывать сообщения

- Stream processing

- Долгое хранение сообщений

- Аналитика в реальном времени

Архитектурные отличия:

1. Модель хранения:

- RabbitMQ: сообщения удаляются после обработки

- Kafka: лог с retention периодом

2. Доставка:

- RabbitMQ: push модель

- Kafka: pull модель

3. Масштабирование:

- RabbitMQ: вертикальное + кластеризация

- Kafka: горизонтальное через партиции

4. Упорядоченность:

- RabbitMQ: в рамках одной очереди

- Kafka: в рамках партиции

Частая ошибка: Использовать Kafka для простых work queues

24
New cards

Как RabbitMQ и Kafka обрабатывают сообщения: по очереди или параллельно?

RabbitMQ:

- По умолчанию последовательно в рамках одного консьюмера

- Параллельность через несколько консьюмеров на одну очередь

- Каждое сообщение обрабатывается только одним консьюмером

- Prefetch позволяет консьюмеру получить несколько сообщений

- Round-robin распределение между консьюмерами

Kafka:

- Параллельность через партиции

- Один консьюмер на партицию в пределах consumer group

- Внутри партиции — строго последовательно

- Параллельность = количество партиций (максимум)

Примеры:

RabbitMQ: 1 очередь, 3 консьюмера

- Сообщение 1 → консьюмер A

- Сообщение 2 → консьюмер B

- Сообщение 3 → консьюмер C

Kafka: 3 партиции, 3 консьюмера

- Партиция 0 → консьюмер A (все сообщения последовательно)

- Партиция 1 → консьюмер B (все сообщения последовательно)

- Партиция 2 → консьюмер C (все сообщения последовательно)

Ключевое отличие: RabbitMQ распределяет сообщения, Kafka распределяет партиции

25
New cards

Какие существуют гарантии доставки сообщений? Объясни at most once, at least once, exactly once.

At most once (максимум один раз):

- Сообщение доставляется 0 или 1 раз

- Возможна потеря

- Нет дубликатов

- Реализация: отправил и забыл, без подтверждений

- Пример: метрики, где потеря некритична

At least once (минимум один раз):

- Сообщение доставляется 1 или более раз

- Нет потерь

- Возможны дубликаты

- Реализация: retry до получения ack

- Пример: важные события, требует идемпотентности

Exactly once (ровно один раз):

- Сообщение доставляется ровно 1 раз

- Нет потерь и дубликатов

- Самая сложная гарантия

- Реализация: идемпотентность + транзакции

Как достигается в разных системах:

- RabbitMQ: publisher confirms + manual ack + идемпотентность

- Kafka: idempotent producer + transactions + exactly-once semantics

Практическое правило:

- Выбирай at least once + идемпотентные консьюмеры

- Это проще чем true exactly once

26
New cards

Возможна ли гарантия exactly once? Если да, то как её достичь?

В теории — невозможна как распределенная проблема (Byzantine Generals Problem).

На практике:

1. At least once + идемпотентность

- Самый практичный подход

- Дубликаты не влияют на результат

2. Kafka Streams/Transactions

- Работает только внутри Kafka

- Если весь pipeline в Kafka — может дать exactly once

- Как только выходишь за пределы Kafka (БД, внешний API) — снова at least once

3. Двухфазный коммит

- Сложно, медленно, хрупко

- Редко используется

Почему exactly once это миф:

- Сеть может дублировать пакеты

- Таймауты не гарантируют что операция не выполнилась

- Консьюмер может упасть между обработкой и ack

Практический совет:

- Не гонись за exactly once

- Делай операции идемпотентными

- Используй at least once доставку

Частая ошибка: Полагаться на exactly once гарантии брокера для критичных операций с внешними системами

27
New cards

Гарантирует ли RabbitMQ и Kafka порядок сообщений? При каких условиях? Как обеспечить строгую очередность в RabbitMQ?

RabbitMQ:

- Гарантирует порядок в пределах одной очереди

- НЕ гарантирует при multiple consumers (prefetch > 1)

- НЕ гарантирует между разными очередями

Условия для порядка в RabbitMQ:

1. Один producer, один consumer

2. Prefetch = 1

3. Без requeue при ошибках

4. Одно соединение

Kafka:

- Гарантирует порядок в пределах партиции

- НЕ гарантирует между партициями

- Ключ партиционирования обеспечивает порядок для группы

Как обеспечить строгую очередность в RabbitMQ:

- Используй только одного консьюмера

- Установи prefetch=1

- Обрабатывай сообщения последовательно

- При ошибке отправляй в DLQ (не requeue)

Альтернатива для RabbitMQ:

- Single Active Consumer feature (если поддерживается)

- Автоматически держит только одного активного консьюмера

Частая ошибка: Ожидать порядок при нескольких консьюмерах

28
New cards

Как справиться с неверным порядком сообщений в распределенной системе?

Простые стратегии:

1. Не полагаться на порядок

- Делай операции независимыми

- Идемпотентность решает многие проблемы

2. Версии или timestamps

- Каждое событие имеет версию

- Применяй только если новее текущей

- Игнорируй устаревшие

3. Ключ партиционирования

- Все события одной сущности в одну партицию/очередь

- Например: все события userId=123 идут вместе

4. Накопление и сортировка

- Собирай события за период

- Сортируй по времени

- Обрабатывай пачкой

Пример с версиями:

- Текущий баланс: 1000₽, версия 5

- Пришло событие: установить 800₽, версия 3

- Действие: игнорировать (старая версия)

Практический совет:

- Лучше проектировать систему без зависимости от порядка

- Если порядок критичен — используй один поток обработки

Частая ошибка: Пытаться синхронизировать распределенные очереди

29
New cards

Что такое Transactional Outbox паттерн? Какие проблемы решает и как реализовать на практике?

Проблема:

Нужно атомарно сохранить данные в БД и отправить событие в брокер. Если сохранили в БД, но не отправили событие — система в несогласованном состоянии.

Решение Outbox:

1. В той же БД создаем таблицу для исходящих событий

2. В транзакции сохраняем бизнес-данные И событие в outbox таблицу

3. Отдельный процесс читает необработанные события и отправляет в брокер

4. После успешной отправки помечает как обработанные

Как это конвертирует гарантии:

- Было: at most once для отправки событий (можем потерять)

- Стало: at least once (благодаря retry из БД)

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

- Консистентность данных и событий

- События не теряются при сбоях

- Можно видеть какие события еще не отправлены

- Retry из коробки

Реализация:

- Polling: фоновый процесс проверяет таблицу

- CDC (Change Data Capture): отслеживание изменений в БД

- Trigger-based: триггеры БД для уведомлений

Частая ошибка: Забыть про очистку старых обработанных событий

30
New cards

Что такое Transactional Inbox паттерн? Зачем он нужен?

Inbox — защита от дубликатов и гарантия обработки входящих сообщений.

Проблема:

Получили сообщение, начали обрабатывать, упали до подтверждения. Брокер доставит повторно — получим дубликат обработки.

Как работает Inbox:

1. Получаем сообщение из брокера

2. Сохраняем в inbox таблицу с уникальным message_id

3. Если такой id уже есть — пропускаем (дубликат)

4. Обрабатываем бизнес-логику в той же транзакции

5. Помечаем как обработанное

Дополнительные возможности:

- Статусы: new, processing, completed, failed

- Timestamps: received_at, started_at, completed_at

- Обработка зависших сообщений (processing больше 5 минут)

Обработка зависших:

- Сообщение в статусе "processing" уже 10 минут

- Скорее всего старый консьюмер умер

- Сбрасываем в "new" и обрабатываем заново

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

- Автоматическая дедупликация

- История всех сообщений

- Возможность переобработки

- Защита от потерь при сбоях

31
New cards

Что такое идемпотентность консьюмера? Как достичь идемпотентности и справиться с дубликатами сообщений?

Идемпотентность — свойство операции давать одинаковый результат при многократном выполнении.

Почему важно:

- At least once доставка = возможны дубликаты

- Сетевые сбои = retry = дубликаты

- Без идемпотентности: двойное списание, дубли записей

Способы достижения:

1. Естественная идемпотентность

- SET операции вместо INCREMENT

- PUT вместо POST в REST

- Upsert вместо Insert

2. Идемпотентные ключи

- Уникальный ID в каждом сообщении

- Проверка перед обработкой

- Сохранение обработанных ID

3. Версионирование

- Обрабатываем только если версия больше

- Игнорируем устаревшие

4. Inbox паттерн

- Сохраняем message_id в БД

- ON CONFLICT DO NOTHING

Пример реализации:

```

ProcessMessage(message):

if (cache.Contains(message.Id))

return // Already processed

BeginTransaction()

// Business logic

cache.Add(message.Id, TTL=24h)

Commit()

```

Частая ошибка: Полагаться только на exactly-once доставку брокера

32
New cards

Что такое Saga паттерн? Когда он применяется?

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

Проблема:

- Нет распределенных ACID транзакций в микросервисах

- Операция затрагивает несколько сервисов

- Нужна консистентность

Как работает:

1. Разбиваем на шаги (локальные транзакции)

2. Каждый шаг публикует событие

3. При ошибке — компенсирующие действия

4. Откатываем в обратном порядке

Пример: Заказ товара

1. Order Service: создать заказ → OrderCreated

2. Payment Service: списать деньги → PaymentProcessed

3. Inventory Service: зарезервировать → ItemsReserved

4. Shipping Service: создать доставку → ShippingCreated

При ошибке на шаге 3:

- Inventory Service → ReservationFailed

- Payment Service: вернуть деньги

- Order Service: отменить заказ

Когда применять:

- Бизнес-транзакция через несколько сервисов

- Можно определить компенсации

- Eventual consistency приемлема

Ограничения:

- Нет изоляции (видны промежуточные состояния)

- Сложность компенсаций

33
New cards

Что такое оркестрация и хореография в контексте Saga? В чем разница, какие преимущества и недостатки у каждого подхода?

Хореография:

- Каждый сервис знает что делать при получении события

- Нет центрального координатора

- Event-driven взаимодействие

Оркестрация:

- Центральный координатор (orchestrator)

- Явно управляет порядком шагов

- Command-driven взаимодействие

Пример хореографии:

OrderService → OrderCreated → PaymentService

PaymentService → PaymentProcessed → InventoryService

InventoryService → ItemsReserved → ShippingService

Пример оркестрации:

OrderSaga:

1. CreateOrder() → OrderService

2. ProcessPayment() → PaymentService

3. ReserveItems() → InventoryService

4. CreateShipping() → ShippingService

Хореография преимущества:

- Слабая связанность

- Простота добавления сервисов

- Нет single point of failure

Хореография недостатки:

- Сложно понять общий flow

- Циклические зависимости

- Трудно отлаживать

Оркестрация преимущества:

- Явный flow в одном месте

- Проще отладка и мониторинг

- Централизованная обработка ошибок

Оркестрация недостатки:

- Дополнительный компонент

- Знает о всех сервисах

- Может стать bottleneck

Рекомендация: Начинай с хореографии, переходи на оркестрацию при усложнении

34
New cards

Какие ключевые метрики нужно мониторить в брокерах сообщений? Что такое backpressure и как с ним справляться?

Ключевые метрики:

RabbitMQ:

- Queue depth (размер очереди)

- Publish/Consume rate

- Consumer utilization

- Connection churn

- Memory/Disk usage

- Unacknowledged messages

Kafka:

- Consumer lag (отставание)

- Partition ISR (in-sync replicas)

- Request rate и latency

- Disk usage и I/O

- Network throughput

- Rebalancing frequency

Backpressure — ситуация когда производитель генерирует сообщения быстрее чем консьюмер обрабатывает.

Признаки:

- Растущие очереди/lag

- Увеличение памяти брокера

- Timeouts

- Отказы в приеме сообщений

Стратегии борьбы:

1. Масштабирование консьюмеров

- Больше инстансов

- Больше партиций в Kafka

2. Rate limiting на producer

- Ограничение скорости отправки

- Circuit breaker

3. Буферизация

- Увеличить размер очередей

- Disk-based очереди

4. Backpressure propagation

- Сообщить producer о перегрузке

- Временная остановка

5. Load shedding

- Отбрасывание некритичных сообщений

35
New cards

Как версионировать схему сообщений? Что делать при изменении структуры сообщения, чтобы не сломать существующих консьюмеров?

Стратегии версионирования:

1. Backward compatibility (рекомендуется)

- Новые консьюмеры понимают старые сообщения

- Добавляем поля, не удаляем

- Опциональные поля с дефолтами

2. Forward compatibility

- Старые консьюмеры понимают новые сообщения

- Игнорируют неизвестные поля

3. Full compatibility

- Backward + Forward

- Самая безопасная стратегия

Практические подходы:

1. Schema versioning в сообщении

```json

{

"version": "2.0",

"eventType": "OrderCreated",

"data": { ... }

}

```

2. Content-Type headers

- application/vnd.order.v1+json

- application/vnd.order.v2+json

3. Разные topics/queues

- orders-v1

- orders-v2

Правила изменений:

- ✅ Добавление опциональных полей

- ✅ Добавление новых типов событий

- ❌ Удаление полей

- ❌ Изменение типов полей

- ❌ Переименование полей

Миграция:

1. Деплой консьюмеров с поддержкой v2

2. Начинаем отправлять v2

3. Когда все v1 обработаны — удаляем поддержку