Взаимодействия между компонентами распределенных систем можно разделить на синхронные и асинхронные.
🔄 Синхронные взаимодействия
Синхронное взаимодействие - это взаимодействие между компонентами системы, когда при вызове другого компонента нужно сразу же получить ответ. Вызывающая сторона ждет ответа вызываемой: либо получает его, либо вызов завершается с ошибкой или по таймауту. Классический пример синхронного взаимодействия - вызов по HTTP.
📝 Пример
Рассмотрим бизнес-сценарий регистрации пользователя в системе, который разбивается на следующие шаги:
- Создать пользователя в БД
- Отправить сообщение по email с ссылкой активации
Представим два компонента системы: сервис пользователей (User) и сервис отправки email (Email). Тогда последовательность выглядит так:
- Пользователь отправляет HTTP-запрос "Создать пользователя" в User
- User сохраняет пользователя в БД и отправляет HTTP-запрос "Отправить email" в Email
⚠️ Проблемы синхронного взаимодействия
Компоненты, взаимодействующие синхронно, являются сильносвязаными. Доступность сценария равна произведению показателей всех компонентов, так как для успешного выполнения нужны все сервисы. Если User и Email имеют показатели доступности 99.8%, то финальный показатель - 99.6%. Чем больше сервисов в цепочке, тем меньше значение показателя.
В итоге пользователи не могут зарегистрироваться, если Email недоступен. Также сервис User ждет ответа Email синхронно, что может приводить к негативному пользовательскому опыту из-за ожидания выполнения запроса "Отправить email" в рамках сценария.
Для решения выше изложенных проблем можно использовать асинхронные взаимодействия.
🚀 Асинхронные взаимодействия
Асинхронное взаимодействие - это взаимодействие между компонентами системы, которое не подразумевает мгновенный ответ.
📨 Брокеры сообщений
Асинхронные взаимодействия почти всегда используют дополнительный компонент системы, брокер сообщений. Брокер обеспечивает возможность доставки сообщений между компонентами системы.
🎯 Решение проблемы
Бизнес выпустил новые требования: регистрация пользователя должна работать при недоступности сервиса Email.
Целевую схему с использованием асинхронного взаимодействия можно описать так:
- Пользователь отправляет HTTP-запрос "Создать пользователя" в User
- User сохраняет пользователя в БД и отправляет событие "Пользователь создан" в брокер сообщений
- Email обрабатывает сообщение "Пользователь создан" и отправляет письмо пользователю.
✅ Преимущества асинхронного подхода
Брокер сообщений позволяет отвязать логику создания пользователя от взаимодействия с сервисом email.
Теперь показатель доступности бизнес-сценария регистрации равен произведению показателя User на показатель брокера. В упрощенных расчетах показатель доступности брокера часто принимают за единицу, так как без него распределенные бизнес-сценарии не выполняются. Поэтому можно допустить, что доступность бизнес-сценария теперь определяется доступностью User. Таким образом удалось отвязать логику сервиса User от Email и добиться создания пользователей даже при неработающем сервисе Email. Рано или поздно сервис email обработает события и отправит письма.
🔧 Дополнительные паттерны
Можно избежать связи с брокером, если использовать паттерн Transactional Outbox, так как он выносит обращение к брокеру из бизнес-сценария в фоновую задачу.
🎯 Вывод
Синхронные взаимодействия используются для клиент-серверных взаимодействий. В распределенных системах используются для получения информации из других компонентов, если нет возможности получить информацию иными путями. Старайся избегать таких взаимодействий.
Асинхронные взаимодействия используются в клиент-серверном взаимодействии для обмена сообщениями. Например, с использованием SignalR. В распределенных системах используются для обмена событиями о бизнес-действиях, как "Пользователь создан" в нашем сценарии, и отправки команд, которые не требуют ответа в другие сервисы. Например, можно было бы заменить событие "Пользователь создан" на команду "Отправить Email".
#техничка #backend