gRPC против REST: начало работы с лучшим протоколом API
Опубликовано: 2022-07-22В современном технологическом ландшафте для большинства проектов требуется использование API. API-интерфейсы обеспечивают связь между службами, которые могут представлять собой единую сложную систему, но также могут находиться на отдельных компьютерах или использовать несколько несовместимых сетей или языков.
Многие стандартные технологии удовлетворяют потребности межсервисных коммуникаций распределенных систем, таких как REST, SOAP, GraphQL или gRPC. В то время как REST является предпочтительным подходом, gRPC является достойным соперником, предлагая высокую производительность, типизированные контракты и отличные инструменты.
Обзор ОТДЫХА
Передача репрезентативного состояния (REST) — это средство получения данных службы или управления ими. REST API обычно строится на протоколе HTTP, используя URI для выбора ресурса и команду HTTP (например, GET, PUT, POST) для выбора желаемой операции. Тело запроса и ответа содержит данные, относящиеся к операции, а их заголовки содержат метаданные. Для иллюстрации рассмотрим упрощенный пример получения товара через REST API.
Здесь мы запрашиваем ресурс продукта с идентификатором 11
и направляем API для ответа в формате JSON:
GET /products/11 HTTP/1.1 Accept: application/json
Учитывая этот запрос, наш ответ (нерелевантные заголовки опущены) может выглядеть так:
HTTP/1.1 200 OK Content-Type: application/json { id: 11, name: "Purple Bowtie", sku: "purbow", price: { amount: 100, currencyCode: "USD" } }
Хотя JSON может быть удобочитаемым для человека, он не оптимален при использовании между службами. Повторяющийся характер ссылок на имена свойств — даже в сжатом виде — может привести к раздуванию сообщений. Давайте посмотрим на альтернативу для решения этой проблемы.
Обзор gRPC
Удаленный вызов процедур gRPC (gRPC) — это основанный на контракте протокол межплатформенной связи с открытым исходным кодом, который упрощает взаимодействие между службами и управляет им, предоставляя набор функций внешним клиентам.
Построенный на основе HTTP/2, gRPC использует такие функции, как двунаправленная потоковая передача и встроенная безопасность транспортного уровня (TLS). gRPC обеспечивает более эффективную связь с помощью сериализованных двоичных полезных данных. Он использует буферы протоколов по умолчанию в качестве механизма сериализации структурированных данных, подобно тому, как REST использует JSON.
Однако, в отличие от JSON, буферы протокола представляют собой нечто большее, чем сериализованный формат. Они включают в себя три другие основные части:
- Язык определения контрактов, найденный в файлах
.proto
(мы будем следовать proto3, последней спецификации языка буферов протоколов). - Сгенерированный код функции доступа
- Библиотеки времени выполнения для конкретных языков
Удаленные функции, доступные в службе (определенные в файле .proto
), перечислены внутри узла службы в файле буфера протокола. Как разработчики, мы можем определять эти функции и их параметры, используя богатую систему типов протокольных буферов. Эта система поддерживает различные числовые типы и типы дат, списки, словари и значения NULL для определения наших входных и выходных сообщений.
Эти определения службы должны быть доступны как для сервера, так и для клиента. К сожалению, не существует механизма по умолчанию для совместного использования этих определений, кроме предоставления прямого доступа к самому файлу .proto
.
Этот пример файла .proto
определяет функцию для возврата записи о продукте с заданным идентификатором:
Строгая типизация и порядок полей в proto3 делают десериализацию сообщений значительно менее трудоемкой, чем парсинг JSON.
Сравнение REST и gRPC
Напомним, что наиболее важными моментами при сравнении REST и gRPC являются:
ОТДЫХАТЬ | gRPC | |
---|---|---|
Кроссплатформенность | Да | Да |
Формат сообщения | Пользовательский, но обычно JSON или XML | Буферы протоколов |
Размер полезной нагрузки сообщения | Средний/большой | Маленький |
Сложность обработки | Высшее (разбор текста) | Нижний (четко определенная бинарная структура) |
Поддержка браузера | Да (родной) | Да (через gRPC-Web) |
Там, где ожидаются менее строгие контракты и частые добавления полезной нагрузки, отлично подходят JSON и REST. Когда контракты имеют тенденцию оставаться более статичными, а скорость имеет первостепенное значение, обычно выигрывает gRPC. В большинстве проектов, над которыми я работал, gRPC оказался легче и производительнее, чем REST.
Реализация службы gRPC
Давайте создадим упрощенный проект, чтобы понять, насколько просто внедрить gRPC.
Создание проекта API
Для начала мы создадим проект .NET 6 в Visual Studio 2022 Community Edition (VS). Мы выберем шаблон ASP.NET Core gRPC Service и назовем как проект (мы будем использовать InventoryAPI
) , так и наше первое решение в нем ( Inventory
) .
Теперь давайте выберем. NET 6.0 (долгосрочная поддержка) для нашего фреймворка:
Определение нашего продукта-услуги
Теперь, когда мы создали проект, VS отображает образец службы определения прототипа gRPC с именем Greeter
. Мы переделаем основные файлы Greeter
в соответствии с нашими потребностями.
- Чтобы создать наш контракт, мы заменим содержимое
greet.proto
фрагментом 1, переименовав файлproduct.proto
. - Чтобы создать наш сервис, мы заменим содержимое файла
GreeterService.cs
фрагментом 2, переименовав файлProductCatalogService.cs
.
Теперь служба возвращает жестко закодированный продукт. Чтобы служба заработала, нам нужно всего лишь изменить регистрацию службы в Program.cs
, чтобы она ссылалась на новое имя службы. В нашем случае мы переименуем app.MapGrpcService<GreeterService>();
в app.MapGrpcService<ProductCatalogService>();
чтобы сделать наш новый API работоспособным.
Справедливое предупреждение: не ваш стандартный тест протокола
Хотя у нас может возникнуть соблазн попробовать это, мы не можем протестировать нашу службу gRPC через браузер, нацеленный на ее конечную точку. Если бы мы попытались это сделать, мы бы получили сообщение об ошибке, указывающее, что связь с конечными точками gRPC должна осуществляться через клиент gRPC.
Создание клиента
Чтобы протестировать нашу службу, давайте воспользуемся базовым шаблоном консольного приложения VS и создадим клиент gRPC для вызова API. Я назвал свой InventoryApp
.
Для удобства давайте сошлемся на относительный путь к файлу, по которому мы будем делиться нашим контрактом. Мы добавим ссылку вручную в файл .csproj
. Затем мы обновим путь и установим режим Client
. Примечание. Я рекомендую вам ознакомиться со структурой локальных папок и быть уверенным в ней, прежде чем использовать относительные ссылки.
Вот ссылки .proto
в том виде, в каком они появляются в файлах сервисного и клиентского проектов:
Файл проекта службы (Код для копирования в файл проекта клиента) | Файл клиентского проекта (После вставки и редактирования) |
---|---|
|
|
Теперь, чтобы вызвать нашу службу, мы заменим содержимое Program.cs
. Наш код выполнит ряд задач:
- Создайте канал, представляющий расположение конечной точки службы (порт может отличаться, поэтому фактическое значение см. в файле
launchsettings.json
). - Создайте клиентский объект.
- Составьте простой запрос.
- Отправьте запрос.
Подготовка к запуску
Чтобы протестировать наш код, в VS мы щелкнем правой кнопкой мыши решение и выберем Set Startup Projects . В диалоговом окне «Страницы свойств решения» мы:
- Выберите переключатель рядом с несколькими запускаемыми проектами и в раскрывающемся меню «Действие» установите для обоих проектов (
InventoryAPI
иInventoryApp
) значение Start . - Нажмите ОК .
Теперь мы можем запустить решение, нажав Start на панели инструментов VS (или нажав клавишу F5 ). Появятся два новых окна консоли: одно, чтобы сообщить нам, что служба прослушивает, другое, чтобы показать нам детали полученного продукта.
Совместное использование контрактов gRPC
Теперь воспользуемся другим методом для подключения клиента gRPC к определению нашего сервиса. Наиболее доступное клиенту решение для совместного использования контрактов — сделать наши определения доступными через URL-адрес. Другие варианты либо очень ненадежны (общий доступ к файлу осуществляется через путь), либо требуют больше усилий (контракт, передаваемый через собственный пакет). Совместное использование через URL-адрес (как это делают SOAP и Swagger/OpenAPI) является гибким и требует меньше кода.
Для начала сделайте файл .proto
доступным как статическое содержимое. Мы обновим наш код вручную, потому что пользовательский интерфейс в действии сборки установлен на «Protobuf Compiler». Это изменение указывает компилятору скопировать файл .proto
, чтобы его можно было обслуживать с веб-адреса. Если бы этот параметр был изменен через пользовательский интерфейс VS, сборка прервалась бы. Итак, наш первый шаг — добавить фрагмент 4 в файл InventoryAPI.csproj
:
Затем мы вставляем код во фрагмент 5 в верхней части файла ProductCatalogService.cs
, чтобы настроить конечную точку для возврата нашего файла .proto
:
А теперь мы добавляем фрагмент 6 непосредственно перед app.Run()
, также в файле ProductCatalogService.cs
:
После добавления фрагментов 4–6 содержимое файла .proto
должно быть видно в браузере.
Новый тестовый клиент
Теперь мы хотим создать новый консольный клиент, который мы будем подключать к нашему существующему серверу с помощью мастера зависимостей VS. Проблема в том, что этот мастер не говорит по HTTP/2. Поэтому нам нужно настроить наш сервер для обмена данными по HTTP/1 и запустить сервер. Теперь, когда наш сервер предоставляет доступ к файлу .proto
, мы можем создать новый тестовый клиент, который подключается к нашему серверу с помощью мастера gRPC.
- Чтобы изменить наш сервер для общения по HTTP/1, мы отредактируем наш JSON-файл
appsettings.json
:- Настройте поле
Protocol
(находится по путиKestrel.EndpointDefaults.Protocols
) для чтенияHttps
. - Сохраните файл.
- Настройте поле
- Чтобы наш новый клиент мог прочитать эту информацию о
proto
, сервер должен быть запущен. Первоначально мы запускали и предыдущий клиент, и наш сервер из диалогового окна Set Startup Projects VS. Настройте серверное решение так, чтобы запускался только серверный проект, а затем запустите решение. (Теперь, когда мы изменили версию HTTP, наш старый клиент больше не может взаимодействовать с сервером.) - Затем создайте новый тестовый клиент. Запустите другой экземпляр VS. Мы повторим шаги, описанные в разделе « Создание проекта API» , но на этот раз выберем шаблон консольного приложения . Мы назовем наш проект и решение
InventoryAppConnected
. - Создав клиентское шасси, мы подключимся к нашему серверу gRPC. Разверните новый проект в обозревателе решений VS.
- Щелкните правой кнопкой мыши Зависимости и в контекстном меню выберите Управление подключенными службами .
- На вкладке Подключенные службы щелкните Добавить ссылку на службу и выберите gRPC .
- В диалоговом окне «Добавить ссылку на службу» выберите параметр « URL » и введите
http
-версию адреса службы (не забудьте взять случайно сгенерированный номер порта изlaunchsettings.json
) . - Щелкните Готово , чтобы добавить ссылку на службу, которую можно легко поддерживать.
Не стесняйтесь проверять свою работу по образцу кода для этого примера. Поскольку под капотом VS сгенерировал того же клиента, который мы использовали в нашем первом цикле тестирования, мы можем дословно повторно использовать содержимое файла Program.cs
из предыдущей службы.
Когда мы меняем контракт, нам нужно изменить определение gRPC нашего клиента, чтобы оно соответствовало обновленному определению .proto
. Для этого нам нужно только получить доступ к подключенным службам VS и обновить соответствующую запись службы. Теперь наш проект gRPC завершен, и теперь легко синхронизировать нашу службу и клиент.
Ваш следующий проект-кандидат: gRPC
Наша реализация gRPC дает представление о преимуществах использования gRPC из первых рук. У REST и gRPC есть свои идеальные варианты использования в зависимости от типа контракта. Однако, когда подходят оба варианта, я рекомендую вам попробовать gRPC — это позволит вам опережать конкурентов в будущем API.