Привет, Хабр. Будущих студентов курса "Software Architect" приглашаем принять участие в открытом вебинаре на тему "Идемпотентность и коммутативность API в очередях и HTTP".Также делимся переводом полезного материала.   В рамках современной микросервисной архитектуры мы можем разделить микросервисы на две основные группы в зависимости от их взаимосвязи и взаимодействия. Первая группа представляет из себя внешние микросервисы, которые напрямую доступны пользователям. В основном это API на основе HTTP, которые используют обычные текстовые сообщения (JSON, XML и т. д.), оптимизированные для использования сторонними разработчиками, использующие передачу репрезентативного состояния (REST) ​​в качестве коммуникационной технологии.  Распространенность и хорошая поддержка REST играют решающую роль в успехе внешних микросервисов. OpenAPI предоставляет четко определенные спецификации для описания, создания, использования и визуализации REST API. Для таких API существуют системы управления API, которые обеспечивают безопасность, ограничение скорости, кеширование и монетизацию наряду с реализацией бизнес-требований. В качестве альтернативы REST API на основе HTTP можно использовать GraphQL, но это уже тема для отдельной статьи. Вторая группа — внутренние микросервисы, которые не предназначены для взаимодействия с внешними системами или сторонними разработчиками. Эти микросервисы взаимодействуют друг с другом для выполнения определенного набора задач. Внутренние микросервисы используют либо синхронный, либо асинхронный режим связи. Во многих реализациях синхронного режима мы наблюдаем использование REST API по HTTP, но это не самая подходящая технология для таких целей. В этой статье мы подробно рассмотрим, как мы можем использовать бинарный протокол, такой как gRPC, в качестве оптимизированного протокола межсервисного взаимодействия. gRPC — это относительно новая парадигма API удаленного вызова процедур (Remote procedure call — RPC) для связи между сервисами. Как и все другие RPC, он позволяет напрямую вызывать методы в серверном приложении на другом компьютере, как если бы это был локальный объект. Как и другие бинарные протоколы, такие как Thrift и Avro, для определения контракта на обслуживание gRPC использует язык описания интерфейсов (interface description language — IDL). gRPC по умолчанию использует HTTP/2 — новейший сетевой транспортный протокол, что делает gRPC намного более быстрым и надежным по сравнению с REST на HTTP/1.1.  Вы можете определить контракт gRPC с помощью Protocol Buffers, где каждое определение сервиса указывает количество методов с ожидаемыми входными и выходными сообщениями, структурой данных параметров и типов возврата. Используя инструменты, предоставляемые основными языками программирования, можно сгенерировать скелет на стороне сервера и код (заглушку) на стороне клиента с помощью того же файла Protocol Buffers, который определяет контракт. Одним из основных преимуществ микросервисной архитектуры является возможность создания различных сервисов, использующих наиболее подходящий для каждого них язык программирования, освобождающая от необходимости написания всей структуры на одном языке. На Рисунке 1 показан сегмент микросервисной архитектуры интернет-магазина розничной торговли, где четыре микросервиса реализованы на Ballerina и Golang, которые работают вместе, чтобы обеспечить базовый функционал розничного интернет-магазина. Поскольку gRPC поддерживается многими основными языками программирования, когда мы определяем сервисные контракты, реализация может выполняться с помощью подходящего под конкретный сервис языка программирования.  Определим контракты для каждого сервиса.  Листинг 1. Контракт для микросервиса Order (order.proto) Order получает товары и количество покупок и возвращает промежуточный итог. Здесь я использую инструмент gRPC Ballerina для создания шаблонного кода службы gRPC и заглушки/клиента соответственно.  Определим контракты для каждого сервиса.  Листинг 2. Фрагмент сгенерированного шаблонного кода (OrderServicesampleservice.bal). Сервис gRPC идеально соотносится ​​с типом service Ballerina, gRPC rpc соотносится ​​с resource function Ballerina, а сообщения gRPC — с типом record.  Для микросервиса Order я создал отдельный проект Ballerina и использовал сгенерированный шаблонный код OrderService для реализации унарного сервиса gRPC.  OrderService вызывается в микросервисе Cart. Для создания клиентской заглушки и клиентского кода мы можем использовать следующую команду Ballerina. Сгенерированная клиентская заглушка имеет как блокирующие, так и неблокирующие удаленные методы. Этот пример кода демонстрирует, как унарный сервис gRPC взаимодействует с блокирующим клиентом gRPC. Листинг 3. Фрагмент сгенерированного кода удаленного объекта для режима блокировки Абстракция удаленного метода Ballerina представляет собой хорошо подогнанную заглушку клиента gRPC, и вы можете сами отметить, насколько код вызова UpdateOrder чист и аккуратен. Микросервис Checkout выставляет окончательный счет, объединяя все промежуточные заказы, полученные от микросервиса Cart. В нашем случае мы собираемся отправлять все промежуточные заказы в виде stream Order сообщений. Листинг 4. Сервисный контракт для микросервиса Checkout (checkout.proto) Чтобы сгенерировать шаблонный код для checkout.proto, вы можете использовать команду ballerina grpc. $ ballerina grpc --mode service --input proto/checkout.proto --output gencode Потоковые сообщения микросервисов Cart (клиент) доступны в качестве аргумента объекта потока, который вы может перебирать с помощью цикла, обрабатывая каждое отдельное сообщение, отправленное клиентом. Вот пример реализации: Листинг 5. службы Фрагмент кода Service для примера реализации CheckoutService(CheckoutServicesampleservice.bal) По завершению клиентского потока возвращается ошибка grpc:EOS, которую можно использовать для определения того, когда следует отправить окончательное ответное сообщение (агрегированный итог) клиенту с помощью caller object. Клиентского код и клиентскую заглушку для CheckoutService можно сгенерировать с помощью следующей команды: Давайте посмотрим на реализацию микросервиса Cart. У микросервиса Cart есть два REST API: один для добавления товаров в корзину, а другой — для окончательного расчета. При добавлении элементов в корзину он получит промежуточный заказ с промежуточным итогом для каждого элемента, выполнив вызов gRPC для микросервиса Order и сохранив его в памяти. Вызов микросервиса Checkout отправит все промежуточные заказы, хранящиеся в памяти, в микросервис Checkout в виде потока gRPC и вернет общую сумму для оплаты. Ballerina использует встроенный тип Stream и абстракции Client Object для реализации потоковой передачи клиента gRPC. На Рисунке 2 показано, как работает потоковая передача клиента Ballerina. Полную реализацию потоковой передачи клиента CheckoutService можно найти в resource function checkout микросервиса Cart. Наконец, в процессе оформления заказа вам нужно совершить gRPC вызов микросервиса Stock, который реализован в Golang, и обновить инвентарь в магазине, вычтя проданные товары. Листинг 6. Контракт для микросервиса Stock (stock.proto) В этом сценарии та же служба UpdateStock будет вызываться с помощью вызова REST API для внешнего API, и с помощью gRPC вызова в качестве межсервисной связи. grpc-gateway — это плагин протокола protoc, который считывает определение сервиса gRPC и генерирует обратный прокси-сервер, который переводит RESTful JSON API в gRPC.    grpc-gateway помогает вам предоставлять ваши API-интерфейсы одновременно в стиле gRPC и REST. Следующая команда генерирует gRPC заглушки для Golang: Следующая команда генерирует код grpc-gateway для Golang: Следующая команда генерирует файл stock.swagger.json: Клонируйте репозиторий git microservices-with-grpc и следуйте инструкциям README.md. gRPC является относительно новой технологией, но его быстрорастущая экосистема и сообщество определенно окажут влияние на развитие микросервисов. Поскольку gRPC является открытым стандартом, его поддерживают все основные языки программирования, что делает его идеальным для работы в среде многоязычных микросервисов. Как правило, мы можем использовать gRPC для всех синхронных коммуникаций между внутренними микросервисами, а также мы можем предоставлять его в виде REST API, используя новые технологии, такие как grpc-gateway. В дополнение к тому, что мы обсуждали в этой статье, такие фичи gRPC, как Deadlines, Cancellation, Channels и поддержка xDS, предоставят разработчикам еще больше возможностей и гибкости для создания высокоэффективных микросервисов. Чтобы узнать больше о поддержке Ballerina gRPC, читайте информацию по следующим ссылкам: Unary Blocking Unary Non-Blocking Server Streaming Client Streaming Bidirectional Streaming Golang уже получил всестороннюю поддержку gRPC, и мы можем расширить микросервисы, написанные на нем, среди прочего, с помощью Interceptor, Deadlines, Cancellation, и Channels от gRPC для повышения безопасности, надежности и отказоустойчивости. Загляните в git репозиторий grpc-go, в котором есть много рабочих примеров по этим концепциям. Также посмотрите видео по теме: Generating Unified APIs with Protocol Buffers and gRPC Writing REST Services for the gRPC curious Using gRPC for Long-lived and Streaming RPCs Узнать подробнее о курсе "Software Architect".Записаться на открытый урок "Идемпотентность и коммутативность API в очередях и HTTP".  Редактор