Команда VK Cloud перевела статью с подробным техническим сравнением двух типов API: HTTP и gRPC. Автор рассказывает о своем опыте работы и описывает нюансы, преимущества и недостатки каждой технологии.

Разработка API на базе HTTP


Самые современные REST API используют модели клиент-серверного взаимодействия «запрос — ответ» и строятся на основе HTTP версии 1.1. Этот протокол существует уже давно и широко поддерживается многими SDK и браузерами. Но есть одна тонкость: протокол HTTP 1.1 полагается только на транзакционное взаимодействие. 

В качестве аналогии обратимся к ситуации, когда вам нужно задать другу несколько вопросов по телефону. С HTTP 1.1 мы звоним другу, задаем один вопрос, получаем ответ и завершаем разговор. Затем снова набираем номер, задаем следующий вопрос и снова кладем трубку. И так, пока не получим всю нужную нам информацию.

Разработчики активно используют REST API, изучают и хорошо понимают принципы его работы. REST согласован с HTTP и методом HTTP-запроса, поэтому разработчикам легко понять, что именно нужно сделать для разработки. 

Также API просто внедрить благодаря относительно пологой кривой обучения: как правило, для переноса данных используют весьма популярный формат JSON. Многие языки программирования относительно быстро выполняют сериализацию и десериализацию JSON, что повышает темпы внедрения. Можно использовать и другие форматы, например XML или BSON, у каждого есть свои преимущества и недостатки.

REST API обеспечивает гибкость индивидуальной настройки API компании. Однако принципы и стандарты проектирования REST часто не соблюдаются. В результате возникает дефицит инструментов для подготовки документации или образцов кода. Здесь на помощь и приходит Postman: вместе со спецификацией OpenAPI он позволяет с легкостью генерировать документацию и образцы кода, задавая структуру, конечные точки и результаты API. Разработчики, планирующие использовать HTTP API, должны представлять, какие бывают эндпоинты и как их правильно использовать.

При использовании REST API могут возникать ответы с большой полезной нагрузкой, особенно когда мы имеем дело со сложными по своей природе ресурсами. В этом случае разработчики беспокоятся о том, что отправляют слишком мало данных. Из-за этой проблемы поиска золотой середины в API-проектировании возник большой интерес к GraphQL, в котором разработчики могут точно указать, какие ресурсы и атрибуты они хотели бы включить в ответ. REST не очень хорошо подходит для клиентов с невысокой производительностью и мобильных устройств с ограниченной пропускной способностью, так что из-за лимитов по работе с данными его нельзя считать идеальным решением.

В GraphQL API, которые тоже строятся на HTTP 1.1 и используют метод POST, устранены многие проблемы поиска золотой середины, свойственные REST API: нужно отправить не «слишком много» данных (которые клиент не примет), и не «слишком мало» (ведь в этом случае клиенту придется обращаться за информацией еще несколько раз). GraphQL задумывался как решение, с помощью которого клиент сможет сделать запрос по имени и сообщить серверу, какие поля данных хочет получить в ответ. Здесь приходится понимать, какие сведения можно извлечь. Для этого разработчикам нужно знать структуру базы данных, а взаимодействие все равно осуществляется в основном в текстовых форматах вроде JSON.

Разработка API на базе gRPC


В 2016 году в Google разработали и выпустили gRPC как высокопроизводительное решение для взаимодействия между микросервисами. С точки зрения подхода к проектированию gRPC основан на RPC, созданном в 1970-х. Так как решение построено на HTTP 2.0, в нем часто используется язык описания данных Protocol Buffers (Protobufs), обеспечивающий строго бинарный формат взаимодействия между клиентом и сервером.

Основные концепции создания RPC API и RESTl API очень похожи. Разработчики определяют правила взаимодействия между клиентом и сервером, а также применяемые методы. Клиенты обращаются к серверам, вызывая методы с помощью аргументов. Однако, в отличие от REST API, который для определения нужного действия использует методы HTTP-запроса GET и POST, RPC API определяет метод в самом URL. А параметры запроса определяют инструкцию, которую необходимо выполнить.

gRPC реализует четыре типа методов обслуживания для передачи данных, которые в целом обеспечивают гибкость использования:

  1. Унарный: клиент обращается с единичным запросом, а сервер высылает единичный ответ, как в случае с REST over HTTP 1.1.
  2. Потоковая передача от сервера к клиенту: клиент может отправлять на сервер несколько запросов, последний из которых подтверждает, что потоковая передача закончилась. Сервер отправляет один ответ на все запросы.
  3. Потоковая передача от клиента к серверу: клиент отправляет исходный запрос, уведомляя сервер, что он готов к получению потока данных. Сервер отправляет несколько ответов, последний из которых подтверждает, что потоковая передача завершена.
  4. Двунаправленная потоковая передача: после исходного унарного соединения между клиентом и сервером оба участника могут отправлять потоки информации.


Типы запросов gRPC в Postman

Protocol Buffers обеспечивает типобезопасный интерфейс и считается «легковесным» форматом взаимодействия. Это очень сжатый формат с немедленным преобразованием в структуры данных, поддерживаемые независимыми языками программирования клиента и сервера. 

Granted, JSON и текстовые форматы перед отправкой тоже можно сжать во многих клиент-серверных системах, поддерживающих алгоритмы сжатия, например gzip.

Основное преимущество HTTP 2.0 и использования Protocol Buffers — это скорость. По утверждению архитектора программного обеспечения Рувана Фернандо, gRPC API имеют производительность в целом в 7–10 раз выше, чем REST API. Важно подчеркнуть, что скорость увеличивается благодаря не только gRPC, но и используемому сетевому уровню и передаче данных. Вернемся к аналогии с телефонным разговором с другом. HTTP 2.0 позволяет позвонить другу один раз, зачитать список вопросов, получить список ответов и завершить звонок. Это сокращает трафик на установление повторных соединений для каждого вопроса.

gRPC позволяет клиенту выполнять «удаленные» (серверные) инструкции, как если бы сервер был частью локальной системы. Поскольку между системами требуется меньше сериализации или десериализации, gRPC выгодно использовать для клиентов с малым уровнем энергопотребления, таких как мобильные и IoT-устройства.

Другое преимущество gRPC — это возможность поиска. Серверы gRPC могут по требованию дополнительно транслировать клиентам список запросов. Такое «отражение в сервере» имеет огромную ценность при работе с gRPC API. Это, конечно, не полноценная замена документации, но список поддерживаемых инструкций упрощает внедрение API. Кроме того, в gRPC встроена функция генерации кода с помощью компилятора protoc.

gRPC API сложно проектировать и создавать, поэтому gRPC довольно трудно внедрить. Проблемы с настройкой и отладкой возникают потому, что сообщения Protocol Buffer по сути своей бинарные и не предназначены для чтения людьми. Хотя в браузеры встроена нативная поддержка библиотек RESTful и типов взаимодействия вроде JSON, для преобразований между HTTP 1.1 и HTTP 2.0 gRPC требуются сторонние библиотеки, такие как gRPC-web.

gRPC начал поддерживать сторонние инструменты и библиотеки недавно, так что командам разработчиков часто приходится больше заниматься внутренними API на основе gRPC, а не внешними API для заказчиков. В результате в Public API Network Postman можно найти лишь несколько gRPC API, например Wechaty и NOVA Security.

Наглядное сравнение HTTP и gRPC для создания API


У создателя API большой выбор. REST соответствует стандартам HTTP и обеспечивает универсальную поддержку, так что для многих команд разработчиков это простое и удобное решение. Объем передаваемых данных в этом случае больше, однако они доступны для просмотра и чтения. Это облегчает разработку и отладку программного обеспечения.

Стиль архитектуры gRPC — отличный выбор для работы с приложениями и микросервисами, написанными на разных языках. Благодаря двунаправленной потоковой передаче контента он эффективен для систем с коммуникационными нагрузками сложнее единичных вопросов и ответов. Его двоичный формат данных гораздо эффективнее, чем передача текстовых RESTful, а использование HTTP 2.0 снижает потребность в повторных подключениях к серверам.
HTTP API
gRPC API
Версия HTTP 
Обычно HTTP 1.1
HTTP 2.0
Модель взаимодействия
Один запрос — один ответ
Один запрос — один ответ и потоковое взаимодействие
Поддержка браузера
Встроенная поддержка
Требуется код из дополнительной библиотеки и прокси
Передача данных
Обычно JSON и XML, но возможны и другие форматы на выбор пользователя
Обычно Protocol Buffers, но допускаются и другие типы
Относительный объем передаваемых данных
Средний или большой, но текст можно сжать до двоичного формата
Небольшой благодаря часто используемому двоичному формату
Типизация данных в полезной рабочей нагрузке
JSON в основном не подлежит строгой типизации. XML может включать данные «о типе», но при этом увеличивается в размере. BSON допускает типизацию данных, но это не распространенный формат. 
Protocol Buffers допускает передачу четко типизированных данных.
SDK и генерирование кода
Для создания примеров кода для генерирования SDK нужно использовать сторонние инструменты, например Postman
Встроенная поддержка генерирования кода
Кроссплатформенные серверы
Да
Да
Сложность обработки
Выше для парсинга текста
Ниже для четко определенной двоичной структуры
Для разработки собственных API необходимы ресурсы. VK Cloud предоставляет их компаниям в облаке. Cloud Servers помогут упростить настройку и обслуживание ваших ИТ-проектов, обеспечив высокую доступность и производительность приложений любой сложности. Новым пользователям даем бонус 3000 рублей на тестирование.

Комментарии (9)


  1. Sannis
    01.02.2023 11:45
    +10

    Команда VK Cloud перевела статью с подробным техническим сравнением двух типов API: HTTP и gRPC.

    Перевели, молодцы. А кто автор?


  1. AYamangulov
    01.02.2023 11:50
    +6

    gRPC API сложно проектировать и создавать, поэтому gRPC довольно трудно внедрить

    Хорошая обзорная статья, но вот этот момент совершенно не раскрыт. Хотелось бы увидеть, как именно реализуется gRPC API, всегда ли необходимо делать собственный gRPC прокси-сервер, который будет транслировать сообщения в спецификации gRPC в несколько запросов к разным другим сервисам (если речь идет о запросе данных из нескольких источников данных), возможно ли добавлять некий "контроллер" gRPC к приложениям-сервисам (отдельным микросервисам) какими-то сравнительно простыми способами по аналогии, как это делается, например, для REST контроллера в Spring приложении? Возможно ли добавление таких контроллеров в приложения, написанные на других стеках? (То есть какова вообще широта поддержки спецификации для множества возможных стеков, на которых пишутся сервисы?)

    Пока что я вижу, что помимо унификации спецификации сообщений для обмена между сервисами, требуется масса промежуточных усилий, не меньших, как мне кажется, если просто писать DTO, объединяющие данные из нескольких источников данных с помощью стандартных возможностей обмена между ними. Мне кажется, что gRPC будет полезен, когда будет масса готовых разработанных прокси-серверов и gPRC-контроллеров в отдельных микросервисах, способных работать с источниками данных большинства или всех видов, используемых в кровавом энтерпрайзе. И чтобы конфигурирование прокси-серверов и gPRC-контроллеров выполнялось не сложнее, чем настройка контроллеров Spring приложения. Только тогда это будет эффективным средством для облегчения работы разработчиков, а не усложнением их работы и замедлением скорости разработки. Business first - давайте не будем забывать об этом важном принципе нашей работы. Этот этап уже достигнут сообществом gRPC или вендорами? Хотелось бы, чтобы уже был достигнут.

    Если я не прав, прошу дать развернутый ответ в деталях - почему именно. Если нужный этап достигнут, хотелось бы увидеть статью с обзором gRPC прокси-серверов и gRPC-контроллеров для разных стеков, и как их внедрять и настраивать.


    1. DeepBlack_31337
      01.02.2023 14:12
      -1

      По мне немного странный вопрос, это как сравнивать холодное с плоским. С REST API много контроллеров - это хорошо, т.к. мы задаем разные вопросы с разной логикой ответов. С gRPC мы устанавливаем канал связи, и желательно что бы он был только один на сервис. При этом определение логики дальнейших действий вкладываем в сам gRPC пакет (идентификатор). gRPC сервер может не только сам обрабатывать ответы, но и пересылать эти вопросы другим своим клиентам (микросервисам). Несомненный плюс такого подхода, это получение и обработка данных - когда она необходима. Если проводить аналогию с Java, очень похоже на асинхронку в RxJava. Еще один несомненный плюс, это одновременная обработка нескольких пакетов в зависимости от количества ядер процессора и открытие не тысячи сокетов, а создание виртуальных групп сокетов на одном соединении. Очень интересный протокол, за ним будущее. По моему опыту, был написан gRPC сервер и встроены клиенты в приклады. И уже через gRPC связал приклады с инфраструктурой.


  1. gmtd
    01.02.2023 12:21
    +11

    1. Почему не рассмотрен случай, когда HTTP API (REST?) работает по HTTP 2.0?

    2. Почему не рассмотрены другие варианты, например JSON-RPC


    1. voroninp
      02.02.2023 05:41

      Можно добавить ещё вариант HTTP1.1+protobuf formatter


  1. dph
    02.02.2023 01:54
    +1

    В статье постоянно путают HTTP API и REST, что вызывает серьезные сомнения в компетентности как автора, так и переводчиков.
    При этом никаких реально важных вещей (документация, версионирование, совместимость с сетевой инфраструктурой) не рассматривают.


  1. nmishin
    02.02.2023 05:46

    А разве не поглотит всех GraphQL API?


    1. TrumanRu
      02.02.2023 12:09
      +2

      На мой взгляд, GraphQL не альтернатива, а один из вариантов подхода к разработке клиент-серверной архитектуры, когда значительная часть информации о структуре данных (а значит и бизнес-логики) уходит на клиента. То есть это фактически не RPC, а, скорее, протокол получения структурированных данных. Серверу при этом достаётся усложнённая (по сравнению с RPC) задача авторизации на доступ к данным.


  1. Shtokarev
    03.02.2023 14:39
    +1

    Честно говоря статья написана или переведена отвратительно (а скорее и то и другое). Не раскрыты полностью все преимущества gPRC (скорость, упаковка, быстрая сериализация, стриминг, генерация под все языки и конечно http2 - и вытекающие из него ). По-моему у gPRC отличные перспективы как у языка межсервисного взаимодействия. Например по следующей схеме: фронт общается со шлюзом через GraphQL (Federation если много данных) а шлюз с микросервисами и они-же между собой посредством gRPC. Таким образом куча микросервисов написанная разными командами на разных языках (в проекте сотни микросервисов на GO, PHP, Java и Node), DTO из proto файлов централизованно генерятся во все используемые языки. Не вдавался как реализованы клиенты для GO, JAVA, PHP но для микросервисов на ноде нет никаких сложностей - все решения и библиотеки вполне зрелые, работают весьма шустро, давно в проде. Есть некоторые сложности связанные с балансировкой микросервисов с gRPC на k8s но это решатся сторонними прокси, тот же Envoy. Так же есть сложности связанные с ошибками в gRPC, но все решаемо (metadata). По сравнению с thrift а тем более с REST гораздо более быстрое и экономное решение.