- PVSM.RU - https://www.pvsm.ru -
[1] Привет, Хаброжители! Мы недавно сдали в типографию книгу Криса Ричардсона [2], цель которой — научить успешно разрабатывать приложения с использованием микросервисной архитектуры. В книге обсуждаются не только преимущества, но и недостатки микросервисов. Вы узнаете, в каких ситуациях имеет смысл применять их, а когда лучше подумать о монолитном подходе.
Основное внимание в книге уделяется архитектуре и разработке. Она рассчитана на любого, в чьи обязанности входят написание и доставка программного обеспечения, в том числе на разработчиков, архитекторов, технических директоров и начальников отделов по разработке.
Ниже представлен отрывок из книги «Использование асинхронного обмена сообщениями»
Как вы видели, разнообразные механизмы IPC подталкивают вас к различным компромиссам. Один из них связан с тем, как механизм IPC влияет на доступность. В этом разделе вы узнаете, что синхронное взаимодействие с другими сервисами в рамках обработки запросов снижает степень доступности приложения. В связи с этим при проектировании своих сервисов вы должны по возможности использовать асинхронный обмен сообщениями.
Сначала посмотрим, какие проблемы создает синхронное взаимодействие и как это сказывается на доступности.
REST — это чрезвычайно популярный механизм IPC. У вас может возникнуть соблазн использовать его для межсервисного взаимодействия. Но проблема REST заключается в том, что это синхронный протокол: HTTP-клиенту приходится ждать, пока сервис не вернет ответ. Каждый раз, когда сервисы общаются между собой по синхронному протоколу, это снижает доступность приложения.
Чтобы понять, почему так происходит, рассмотрим сценарий, представленный на рис. 3.15. У сервиса Order есть интерфейс REST API для создания заказов. Для проверки заказа он обращается к сервисам Consumer и Restaurant, которые тоже имеют REST API.
Создание заказа состоит из такой последовательности шагов.
Поскольку эти сервисы используют HTTP, все они должны быть доступны, чтобы приложение FTGO смогло обработать запрос CreateOrder. Оно не сможет создать заказ, если хотя бы один из сервисов недоступен. С математической точки зрения доступность системной операции является произведением доступности сервисов, которые в нее вовлечены. Если сервис Order и те два сервиса, которые он вызывает, имеют доступность 99,5 %, то их общая доступность будет 99,5 %3 = 98,5 %, что намного ниже. Каждый последующий сервис, участвующий в запросе, делает операцию менее доступной.
Эта проблема не уникальна для взаимодействия на основе REST. Доступность снижается всякий раз, когда для ответа клиенту сервис должен получить ответы от других сервисов. Здесь не поможет даже переход к стилю взаимодействия «запрос/ответ» поверх асинхронных сообщений. Например, если сервис Order пошлет сервису Consumer сообщение через брокер и примется ждать ответа, его доступность ухудшится.
Если вы хотите максимально повысить уровень доступности, минимизируйте объем синхронного взаимодействия. Посмотрим, как это сделать.
Существует несколько способов уменьшения объема синхронного взаимодействия с другими сервисами при обработке синхронных запросов. Во-первых, чтобы полностью избежать этой проблемы, все сервисы можно снабдить исключительно асинхронными API. Но это не всегда возможно. Например, публичные API обычно придерживаются стандарта REST. Поэтому некоторые сервисы обязаны иметь синхронные API.
К счастью, чтобы обрабатывать синхронные запросы, вовсе не обязательно выполнять их самому. Поговорим о таких вариантах.
Использование асинхронных стилей взаимодействия
В идеале все взаимодействие должно происходить в асинхронном стиле, описанном ранее в этой главе. Представьте, к примеру, что клиент приложения FTGO применяет для создания заказов асинхронный стиль взаимодействия вида «запрос/асинхронный ответ». Чтобы создать заказ, он отправляет сообщение с запросом сервису Order. Затем этот сервис асинхронно обменивается сообщениями с другими сервисами и в итоге возвращает клиенту ответ (рис. 3.16).
Клиент и сервис общаются асинхронно, отправляя сообщения через каналы. Ни один из участников этого взаимодействия не блокируется в ожидании ответа.
Такая архитектура была бы чрезвычайно устойчивой, потому что брокер буферизирует сообщения до тех пор, пока их потребление не станет возможным. Но проблема в том, что у сервисов часто есть внешний API, который использует синхронный протокол вроде REST и, как следствие, обязан немедленно отвечать на запросы.
Если у сервиса есть синхронный API, доступность можно улучшить за счет репликации данных. Посмотрим, как это работает.
Репликация данных
Одним из способов минимизации синхронного взаимодействия во время обработки запросов является репликация данных. Сервис хранит копию (реплику) данных, которые ему нужны для обработки запросов. Чтобы поддерживать реплику в актуальном состоянии, он подписывается на события, публикуемые сервисами, которым эти данные принадлежат. Например, сервис Order может хранить копию данных, принадлежащих сервисам Consumer и Restaurant. Это позволит ему обрабатывать запросы на создание заказов, не обращаясь к этим сервисам. Такая архитектура показана на рис. 3.17.
Сервисы Consumer и Restaurant публикуют события всякий раз, когда их данные меняются. Сервис Order подписывается на эти события и обновляет свою реплику.
В некоторых случаях репликация данных — это хорошее решение. Например, в главе 5 описывается, как сервис Order реплицирует данные сервиса Restaurant, чтобы иметь возможность проверять элементы меню. Один из недостатков этого подхода связан с тем, что иногда он требует копирования больших объемов данных, что неэффективно. Например, если у нас много заказчиков, хранить реплику данных, принадлежащих сервису Consumer, может оказаться непрактично. Еще один недостаток репликации кроется в том, что она не решает проблему обновления данных, принадлежащих другим сервисам.
Чтобы решить эту проблему, сервис может отсрочить взаимодействие с другими сервисами до тех пор, пока он не ответит своему клиенту. Речь об этом пойдет далее.
Завершение обработки после возвращения ответа
Еще один способ устранения синхронного взаимодействия во время обработки запросов состоит в том, чтобы выполнять эту обработку в виде следующих этапов.
Во время обработки запроса сервис не обращается синхронно ни к каким другим сервисам. Вместо этого он шлет им асинхронные сообщения. Данный подход обеспечивает слабую связанность сервисов. Как вы увидите в следующей главе, этот процесс часто реализуется в виде повествования.
Представьте, что сервис Order действует таким образом. Он создает заказ с состоянием PENDING и затем проверяет его, обмениваясь асинхронными сообщениями с другими сервисами. На рис. 3.18 показано, что происходит при вызове операции createOrder(). Цепочка событий выглядит так.
И так далее…
Сервис Order может получить сообщения ConsumerValidated и OrderDetailsValidated в любом порядке. Чтобы знать, какое из них он получил первым, он меняет состояние заказа. Если первым пришло сообщение ConsumerValidated, состояние заказа меняется на CONSUMER_VALIDATED, а если OrderDetailsValidated — на ORDER_DETAILS_VALIDATED. Получив второе сообщение, сервис Order присваивает заказу состояние VALIDATED.
После проверки заказа сервис Order выполняет оставшиеся шаги по его созданию, о которых мы поговорим в следующей главе. Замечательной стороной этого подхода является то, что сервис Order сможет создать заказ и ответить клиенту, даже если сервис Consumer окажется недоступным. Рано или поздно сервис Consumer восстановится и обработает все отложенные сообщения, что позволит завершить проверку заказов.
Недостаток возвращения ответа до полной обработки запроса связан с тем, что это делает клиент более сложным. Например, когда сервис Order возвращает ответ, он дает минимальные гарантии по поводу состояния только что созданного заказа. Он отвечает немедленно, еще до проверки заказа и авторизации банковской карты клиента. Таким образом, чтобы узнать о том, успешно ли создан заказ, клиент должен периодически запрашивать информацию или же сервис Order должен послать ему уведомительное сообщение. Несмотря на всю сложность этого подхода, во многих случаях стоит предпочесть его, особенно из-за того, что он учитывает проблемы с управлением распределенными транзакциями, которые мы обсудим в главе 4. В главах 4 и 5 я продемонстрирую эту методику на примере сервиса Order.
» Более подробно с книгой можно ознакомиться на сайте издательства [3]
» Оглавление [4]
» Отрывок [5]
Для Хаброжителей скидка 30% на предзаказ книги по купону — Микросервисы
Автор: ph_piter
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/knigi/322565
Ссылки в тексте:
[1] Image: https://habr.com/ru/company/piter/blog/458344/
[2] Криса Ричардсона: https://www.amazon.com/Chris-Richardson/e/B00MBVFJHU/ref=dp_byline_cont_book_1
[3] сайте издательства: https://www.piter.com/collection/soon/product/mikroservisy-patterny-razrabotki-i-refaktoringa
[4] Оглавление: https://storage.piter.com/upload/contents/978544610996/978544610996_X.pdf
[5] Отрывок: https://storage.piter.com/upload/contents/978544610996/978544610996_p.pdf
[6] Источник: https://habr.com/ru/post/458344/?utm_campaign=458344&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.