Вопрос или проблема
Существует ли способ избежать множества вызовов к другим микросервисам из одного запроса сервиса?
Я разрабатываю веб-чат приложение на основе микросервисов с использованием Spring Boot и Websockets.
Сейчас меня беспокоит следующее: похоже, что каждому из моих микросервисов необходимо делать множество вызовов к другим сервисам для выполнения одного запроса, что делает всю систему сильно связанной.
Например, когда пользователь A подключается к приложению, ему необходимо получить все свои разговоры (давайте сейчас скажем, что это только один на один), поэтому он отправляет запрос в сервис разговоров с идентификатором пользователя, и этот сервис извлекает все разговоры пользователя из БД, и здесь начинается проблема:
- Каждый объект разговора имеет атрибут списка идентификаторов участников (пользователь A и пользователь B), поэтому, используя идентификатор другого пользователя (получателя, пользователь B), сервис разговоров вызывает для каждого разговора:
- Сервис пользователей для получения имени пользователя
- Сервис изображений профиля для получения изображения пользователя
- Сервис присутствия для статуса онлайн/офлайн
- Сервис непрочитанных сообщений для получения количества непрочитанных сообщений в разговоре
В конце концов, это очень много работы и вызовов для всего лишь одного запроса, и, очевидно, я чувствую, что здесь что-то не так, но не могу разобраться, какой путь лучше всего выбрать в этой ситуации.
Я был бы очень признателен за ваши отзывы и критику, заранее спасибо!!
Я пытался “сохранять” общие данные пользователей в одном сервисе, например, сервис пользователей теперь хранит изображение профиля (может, нет необходимости в сервисе изображений профиля?), и вместо того, чтобы просто сохранять идентификаторы участников в объектах разговора, также их имена пользователей, но в конце концов это все равно требует много вызовов от сервиса разговоров, если пользователю нужно извлечь много его разговоров сразу.
Ответ или решение
Вопрос, который вы подняли, является распространенной проблемой в архитектуре микросервисов. Когда один сервис делает множество вызовов к другим сервисам для получения информации, это может привести к проблемам с производительностью и усложнению кода. Ниже приведены несколько стратегий, которые помогут вам оптимизировать взаимодействие между микросервисами и избежать частых вызовов к другим сервисам в ответ на один запрос.
1. Агрегация данных
Один из способов снизить количество вызовов — это использовать паттерн агрегатора. Вместо того чтобы Conversation Service вызывал User Service, Profile Image Service и другие службы отдельно для каждой беседы, вы можете создать отдельный сервис, который будет агрегировать все необходимые данные и возвращать их в одном запросе. Это будет «мост» между Conversation Service и другими сервисами. Например, UserDetailsService
может служить для получения всех необходимых данных о пользователе в одном запросе.
2. Кэширование
Использование кэширования может значительно снизить нагрузку на микросервисы, особенно если данные, получаемые из других сервисов, не меняются часто. Вы можете кэшировать результаты запросов к User Service и другим сервисам на уровне Conversation Service. Таким образом, при повторном запросе данные могут быть предоставлены из кэша, без дополнительного обращения к другим сервисам.
3. Объединение сервисов
Если некоторые микросервисы постоянно вызываются друг другом, возможно, стоит рассмотреть возможность объединения этих сервисов. В вашем случае, если User Service и Profile Image Service могут брать на себя схожую функциональность, их можно объединить в один User Profile Service. Это уменьшит количество межсервисных вызовов и упростит структуру.
4. Подготовка избыточных данных
Создайте избыточные данные в вашей базе данных. Например, когда Conversation Service создает объект беседы, он может уже включать в него детальную информацию о участниках (имена, фотографии профиля, статус онлайн/офлайн). Это может потребовать некоторого избыточного хранения данных, но уменьшит сложность и время ответа при обслуживании запросов.
5. Использование событийной архитектуры
Используйте подход событийной архитектуры, чтобы разряжать связи между сервисами. Вместо того чтобы запрашивать данные непосредственно, Conversation Service может подписаться на события, которые объясняют изменения в статусе пользователей или сообщениях. Например, когда пользователь изменяет свой статус на «онлайн», можно отправить соответствующее событие, которое обновит информацию в кэше Conversation Service.
6. GraphQL
Если ваша архитектура это допускает, рассмотрите возможность интеграции GraphQL. GraphQL позволяет клиенту запрашивать только ту информацию, которая ему необходима, что может сократить количество запросов и уменьшить нагрузку на сервер.
Заключение
Каждое из предлагаемых решений имеет свои плюсы и минусы, и оптимальный выбор зависит от ваших конкретных требований и архитектуры. Комбинирование этих подходов также может быть весьма эффективным. Важно постоянно анализировать требования приложения и производительность системы, чтобы находить оптимальные архитектурные решения. Наличие небольшой команды сразу позволяет учитывать возможности различных подходов и находить оптимальные пути интеграции.