Что такое gRPC? Объяснение буферов протокола, потоковой передачи и архитектуры
gRPC - это мощный фреймворк для работы с удаленными вызовами процедур. RPC позволяют писать код, как если бы он был запущен на локальном компьютере, даже если он может выполняться на другом компьютере.
Последние несколько дней я глубоко погрузился в gRPC. В этой статье я собираюсь поделиться некоторыми из своих больших открытий.
Обратите внимание, что я сосредоточусь больше на концепциях, чем на деталях реализации. Вы узнаете основную архитектуру самого gRPC. Вы также узнаете:
- Почему gRPC так широко используется разработчиками
- Как это работает так хорошо
- И как все это работает под капотом.
Вернемся немного назад
Прежде чем мы перейдем к gRPC, мы должны взглянуть на то, что такое удаленный вызов процедур.
RPC - это форма взаимодействия клиент-сервер, в которой используется вызов функции, а не обычный HTTP-вызов.
Он использует IDL (язык определения интерфейса) как форму контракта на вызываемые функции и на тип данных.
Если вы все еще этого не осознали, RPC в gRPC означает удаленный вызов процедуры. И да, gRPC действительно копирует этот архитектурный стиль взаимодействия клиент-сервер с помощью вызовов функций.
Так что gRPC технически не новая концепция. Скорее он был заимствован из этой старой техники и усовершенствован, что сделало его очень популярным всего за 5 лет.
Обзор gRPC
В 2015 году Google открыла исходный код своего проекта, который в конечном итоге получил название gRPC. Но что на самом деле означает «g» в gRPC?
Google меняет значение буквы «g» для каждой версии до такой степени, что они даже сделали README, чтобы перечислить все значения.
С момента появления gRPC он приобрел довольно большую популярность, и многие компании его используют.
Что делает gRPC таким популярным?
Существует множество причин, по которым gRPC так популярен:
- Абстракция - это просто (это вызов функции)
- Поддерживается на многих языках.
- Это очень эффективно
- HTTP-вызовы часто сбивают с толку, поэтому это упрощает
И помимо всех вышеперечисленных причин, gRPC популярен, потому что очень популярны микросервисы.
Микросервисы часто запускают несколько сервисов на разных языках программирования. У них также часто бывает много сервисов для обслуживания взаимодействий.
Именно здесь gRPC помогает больше всего, предоставляя поддержку и возможности для решения типичных проблем, возникающих в таких ситуациях.
gRPC очень популярен в сервисе для сервисных вызовов, поскольку часто HTTP-вызовы труднее понять с первого взгляда.
Обдумывать функции gRPC гораздо проще, поэтому разработчикам не нужно беспокоиться о написании большого количества документации, потому что сам код должен все объяснять.
Некоторые службы также могут быть написаны на разных языках, и gRPC поставляется с несколькими библиотеками для поддержки этого.
Производительность - это вишенка на вершине - и это большая изюминка.
Архитектура gRPC
Я несколько раз упоминал, что производительность gRPC очень хороша, но вы можете задаться вопросом, что делает его таким хорошим? Что делает gRPC намного лучше, чем RPC, когда их дизайн очень похож?
Вот несколько ключевых отличий, которые делают gRPC таким производительным.
HTTP / 2
HTTP с нами давно. Сейчас почти все серверные службы используют этот протокол.
Как видно из рисунка выше, HTTP / 1.1 долгое время оставался актуальным.
Затем в 2015 году появился HTTP / 2, который по сути заменил HTTP / 1.1 как самый популярный транспортный протокол в Интернете.
Если вы помните, что 2015 год был годом выхода gRPC, это было отнюдь не совпадение. HTTP / 2 также был создан Google для использования gRPC в своей архитектуре.
HTTP / 2 - одна из главных причин, по которой gRPC может работать так хорошо. И в следующем разделе вы увидите, почему.
Мультиплексирование запроса / ответа
В традиционном протоколе HTTP невозможно отправить несколько запросов или получить несколько ответов вместе в одном соединении. Для каждого из них необходимо будет создать новое соединение.
Этот вид мультиплексирования запроса / ответа стал возможным в HTTP / 2 с введением нового уровня HTTP / 2, называемого двоичным кадрированием.
Этот двоичный уровень инкапсулирует и кодирует данные. На этом уровне HTTP-запрос / ответ разбивается на кадры.
Кадр заголовков содержит типичную информацию заголовков HTTP, а кадр данных содержит полезную нагрузку. Используя этот механизм, можно получать данные из нескольких запросов в одном соединении.
Это позволяет получать полезные данные из нескольких запросов с одним и тем же заголовком, таким образом идентифицируя его как один запрос.
Сжатие заголовка
Возможно, вы сталкивались со многими случаями, когда заголовки HTTP даже больше, чем полезная нагрузка. И HTTP / 2 имеет очень интересную стратегию под названием HPack, чтобы справиться с этим.
Во-первых, все в HTTP / 2 кодируется перед отправкой, включая заголовки. Это действительно помогает с производительностью, но это не самое главное в сжатии заголовков.
HTTP / 2 отображает заголовок как на стороне клиента, так и на стороне сервера. Исходя из этого, HTTP / 2 может узнать, содержит ли заголовок то же значение, и отправляет значение заголовка, только если оно отличается от предыдущего заголовка.
Как видно на картинке выше, запрос №2 отправит только путь, поскольку другие значения точно такие же. И да, это значительно сокращает размер полезной нагрузки и, в свою очередь, еще больше улучшает производительность HTTP / 2.
Буфер протокола, он же Protobuf
Protobuf - это наиболее часто используемый IDL (язык определения интерфейса) для gRPC. Здесь вы в основном храните свои данные и функциональные контракты в виде прото-файла.
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}
Поскольку это форма контракта, и клиент, и сервер должны иметь один и тот же прото-файл. Файл proto действует как посреднический контракт для клиента для вызова любых доступных функций с сервера.
Protobuf также владеет механизмами, в отличие от обычного REST API, который просто отправляет строки JSON в виде байтов. Эти механизмы позволяют значительно уменьшить полезную нагрузку и повышать производительность.
Метод кодирования, который использует Protobuf, довольно сложен. Если вы хотите глубже понять, как это работает, ознакомьтесь с этой исчерпывающей документацией.
Что еще предлагает gRPC?
Теперь вы должны иметь базовое представление об архитектуре gRPC, о том, как он работает и на что способен.
Но вот еще несколько интересных вещей, которые предлагает нам gRPC.
Метаданные
Вместо использования обычного заголовка HTTP-запроса в gRPC есть нечто, называемое метаданными. Метаданные - это тип данных "ключ-значение", которые могут быть установлены на стороне клиента или сервера.
Header
могут быть назначены на стороне клиента, в то время как серверы могут назначать Header
и Trailers
при условии, что они оба находятся в форме метаданных.
Потоковая передача
Потоковая передача - одна из основных концепций gRPC, при которой в одном запросе может выполняться несколько вещей. Это стало возможным благодаря возможности мультиплексирования HTTP / 2, упомянутой ранее.
Есть несколько видов стриминга:
- RPC потоковой передачи сервера: когда клиент отправляет один запрос, а сервер может отправить обратно несколько ответов. Например, когда клиент отправляет запрос на домашнюю страницу со списком из нескольких элементов, сервер может отправлять ответы отдельно, что позволяет клиенту использовать отложенную загрузку.
- Клиентский Streaming RPC: когда клиент отправляет несколько запросов, а сервер отправляет только один ответ. Например, zip / чанк, загруженный клиентом.
- Двунаправленный потоковый RPC: когда и клиент, и сервер отправляют сообщения друг другу одновременно, не дожидаясь ответа.
Перехватчики
gRPC поддерживает использование перехватчиков для своего запроса / ответа. Перехватчики, ну, перехватывают сообщения и позволяют изменять их.
Звучит знакомо? Если вы играли с HTTP-процессами в REST API, перехватчики очень похожи на промежуточное ПО.
Библиотеки gRPC обычно поддерживают перехватчики и позволяют легко реализовать. Перехватчики обычно используются для:
- Изменяет запрос / ответ перед передачей. Его можно использовать для предоставления обязательной информации перед отправкой на клиент / сервер.
- Позволяют вам управлять каждым вызовом функции, например, добавлять дополнительные записи для отслеживания времени отклика.
Балансировки нагрузки
Если вы еще не знакомы с балансировкой нагрузки, это механизм, который позволяет распределять клиентские запросы по нескольким серверам.
Но балансировка нагрузки обычно выполняется на уровне прокси (например, NGINX). Так почему я говорю об этом здесь?
Оказывается, gRPC поддерживает метод балансировки нагрузки клиентом. Он уже реализован в библиотеке Golang и может быть легко использован.
Хотя это может показаться какой-то безумной магией, на самом деле это не так. Есть какой-то DNS-преобразователь для получения списка IP-адресов и алгоритм балансировки нагрузки под капотом.
Отмена вызова
Клиенты gRPC могут отменить вызов gRPC, когда ему больше не нужен ответ. Однако откат на стороне сервера невозможен.
Эта функция особенно полезна для потоковой передачи на стороне сервера, когда могут поступать несколько запросов к серверу. Библиотека gRPC оснащена шаблоном метода наблюдателя, чтобы знать, отменен ли запрос, и позволяет ему отменить сразу несколько соответствующих запросов.
Заключение
Все, чем я поделился сегодня, лишь поверхностно описывает, что такое gRPC, на что он способен и примерно как работает.
Я искренне надеюсь, что эта статья помогла вам больше узнать о gRPC. Но предстоит еще многое узнать, так что не останавливайтесь на достигнутом!
Спасибо за прочтение!