Знакомство с gRPC
25 ноября 2022 г.Что такое RPC?
В распределенных системах нам часто приходится обмениваться данными между различными службами. Код, который может выглядеть как локальный вызов функции, на самом деле выполняется на другом узле в другой системе. Это известно как удаленный вызов процедуры или RPC.
Ниже приведен фрагмент кода для демонстрации идеи:
// Imagine a client (an online shop) communicating with a server (payment processor)
// we have an Order object in the shop with an associated item name and price
Order newOrder = new Order();
newOrder.writeItemName("playstation5");
newOrder.writePrice("499.99");
// we call a credit card service to process the payment
// Note: the key here is that the credit card service is on a completely different network node.
// it is not a local method call.
Payment payment = creditCardService.processPayment(parseInt(newOrder.Price, 10))
//...depending on whether or not the payment is successful, you can do further work.
Для реализации RPC обычно используется инфраструктура RPC. Чтобы клиент действительно успешно вызывал метод, существующий на другом узле, фреймворк предоставляет вам то, что известно как «заглушка». Эта заглушка обеспечивает видимость метода, который на самом деле существует только на другой стороне (сервере). Он преобразует запросы, ответы и методы в код, который можно отправить службе, которая фактически выполняет намеченное выполнение функции. Для этого преобразования используется термин «маршалинг». Сервер RPC будет захватывать пакеты, отправленные по сети, «распаковывать» сообщение и выполнять вызов функции. Ответ сервера клиенту потребует еще одного цикла маршал-демаршал.
:::информация Интересное примечание: протокол RPC старше REST и используется с 1970-х годов.
:::
Что такое услуга?
В определении службы указывается, какие методы можно вызывать удаленно, а также указываются типы объектов, используемых для инициирования вызова RPC, а также ожидаемый тип возвращаемого значения. Используя приведенный выше пример, вы можете представить, что определение службы processPayment
ожидает цену и возвращает логическое значение, указывающее на успех или неудачу платежа. Позже мы увидим более конкретный пример.
Что отличает gRPC?
Основное отличие состоит в том, что вместо использования JSON или XML gRPC адаптирует обычную инфраструктуру RPC для использования «протокольных буферов» или protobuf
в качестве языка определения интерфейса (этот формат был создан Google в 2008 году). ). Этот двоичный формат данных очень легкий и быстрый, поэтому его предпочитают в тех случаях, когда вы цените скорость и хотите свести к минимуму использование полосы пропускания. gRPC построен на основе HTTP/2, поэтому он идеально подходит для двунаправленной связи; клиент может инициировать долгоживущее соединение с сервером, через которое можно непрерывно отправлять вызовы RPC.
Какие существуют типы методов службы gRPC?
gRPC предлагает 4 типа методов обслуживания.
- Унарные RPC: это похоже на обычный вызов функции, когда клиент отправляет один запрос и получает в ответ один ответ.
- Серверная потоковая передача RPC: здесь клиент отправляет один запрос, но получает в ответ поток ответов.
- Клиентские потоковые RPC: клиент отправляет поток сообщений, но получает ответ только после того, как сервер завершит обработку всего потока.
- Двунаправленная потоковая передача RPC: включает два независимых потока. И клиент, и сервер отправляют потоки сообщений, используя поток чтения-записи.
Создание метода унарной службы с использованием Go и gRPC
Прежде чем мы начнем, убедитесь, что у вас есть необходимые условия, перейдя по этой ссылке. :
Не беспокойтесь о примере кода, так как мы будем создавать свой собственный.
<цитата>Почему есть две разные загрузки?
Начиная с версии 1.20.0, модуль protobuf
не поддерживает определения службы gRPC. Плагин protoc-gen-go
, входящий в состав этого модуля, предназначен для компилятора буфера протокола для генерации кода Go. Но чтобы сгенерировать привязки Go для определений службы gRPC, необходимо также загрузить подключаемый модуль protoc-gen-go-grpc
.
Мы создадим базовый унарный сервис с серверным и клиентским компонентами. Идея состоит в том, чтобы реализовать метод SayHello, в котором клиент отправляет запрос со своим именем, а сервер отвечает приветствием, включающим имя. Нам нужно определить наш сервис и методы, сгенерировать файлы protobuf
, и мы будем готовы играть с нашим кодом!
Шаг 1. Создайте каталог для нашего проекта
Создайте новый каталог с именем grpc_noon
и создайте вложенную папку с именем proto
. Перейдите к proto
и создайте 2 подпапки с именами server
и client
соответственно. Теперь ваша папка должна выглядеть так, как показано на изображении ниже:
Шаг 2. Создайте определение службы
Во вложенной папке proto
создайте файл с именем greeter.proto
.
Перейдите к папке proto
и откройте терминал. Введите следующий код:
перейти к моду инициировать example.com/grpc-greeter
Давайте быстро пробежимся по тому, что мы только что сделали. Чтобы отслеживать зависимости при создании модуля, мы используем go mod init
, но обычно путь к модулю включает его источник в виде URL-адреса репозитория. В тех случаях, когда мы можем публиковать модули для использования другими, это обычная практика. Для нас example.com
— это просто URL-адрес-заполнитель, который используется внутри в качестве точного указателя на модуль. При желании вы можете использовать вместо этого локальный путь, например ./grpc-greeter
.
Теперь мы можем определить нашу службу и любые методы RPC, которые мы хотим использовать.
syntax = "proto3"; // specify the syntax
package greeter; // declare the greeter package
option go_package = "example.com/grpc-greeter;grpc_greeter"; // direct the go package to our module path
service Greeter { // define our service and the rpc methods we'd like to call
rpc SayHello(Message) returns (MessageResponse) {}
}
message Message { // define the request with expected parameters
string name = 1;
}
message MessageResponse { // define the response with expected parameters
string greeting = 1;
}
option
определен, чтобы помочь на следующем шаге, но в остальном мы просто определяем ожидаемое взаимодействие, которое мы хотим между нашим клиентом и сервером.
Теперь, когда определение сервиса завершено, мы можем сгенерировать необходимые файлы protobuf
.
В папке proto
выполните следующую команду:
протокол --go_out=. --go_opt=paths=относительный_источник --go-grpc_out=. --go-grpc_opt=paths=source_relative ./greeter.proto
На этом этапе мы используем плагины, которые мы скачали ранее, для создания наших файлов proto
по определенным путям. .
просто ссылается на текущий каталог, поэтому мы диктуем расположение выходных каталогов. На этом этапе ваша папка должна выглядеть так (левая боковая панель):
Если вы посмотрите на сгенерированные файлы, вы увидите, что реализация сервера и клиента находится в стадии разработки. файл greeter_gRPC_pb.go
, тогда как логика сериализации и десериализации для определенной службы находится в файле greeter.pb.go
.
Шаг 3. Создайте сервер gRPC
Перейдите к подпапке server
.
Во-первых, давайте объявим имя пакета и импортируем то, что нам нужно.
Далее мы воспользуемся файлом protobuf
для создания нашей серверной структуры и функции, которую мы хотим вызывать из клиента.
Наконец, давайте запустим сервер в нашей функции main
и настроим его для работы на определенном порту.
Чтобы убедиться, что он работает, вы можете запустить go run Greeter_server.go
, и вы увидите, что он запущен и работает!
Шаг 4. Создайте клиент gRPC
Перейдите к подпапке client
.
Здесь мы хотим сделать 3 вещи:
- Инициализируйте подключение клиента gRPC и наберите номер сервера. Мы будем использовать библиотечные методы
grpc
для достижения обеих целей. - Создайте клиент
Greeter
и выполните вызов RPC с помощью нашего методаSayHello
(не забудьте передать имя!). Мы будем использовать методы из сгенерированных файловprotobuf
, чтобы сделать и то, и другое. - Наконец, запустите клиент и посмотрите ответ! В строке 27 на изображении ниже вы можете видеть, как мы используем поле
Greeting
из структуры, которую мы определили в нашем файлеproto
. Примечание. Независимо от того, какой регистр вы используете в своих определениях, все файлыprotobuf
будут использовать верхний регистр для полей и определений методов.
Шаг 5. Запустите клиент и проверьте ответ
Предполагая, что ваш сервер уже работает с адресом/портом, и клиент набирает тот же адрес/порт, теперь вы можете запустить свой клиент. В случае успеха вы должны увидеть что-то вроде изображения ниже на стороне сервера:
На стороне клиента вы увидите зарегистрированное сообщение следующего содержания:
2022/11/23 19:36:47 Response from server: Bob`
Заключение
Вы успешно настроили клиент и сервер gRPC и определили методы службы, которые можно использовать с аргументом! Унарные типы служб можно использовать во многих случаях, но если вы хотите попробовать что-то еще, вы можете поэкспериментировать с двунаправленными типами служб. Надеюсь, это помогло.
Ссылки:
https://www.youtube.com/watch?v=hVrwuMnCtok
https://grpc.io/docs/what-is-grpc/core-concepts/
https://www.youtube.com/watch?v=S2osKiqQG9s
https://www.youtube.com/watch?v=YudT0nHvkkE
https://betterprogramming.pub/understanding-grpc-60737b23e79e
https://betterprogramming.pub/understanding-protocol-buffers-43c5bced0d47
Спасибо этим замечательным инженерам за их вклад и помощь:
https://github.com/aryan-binazir
https://github.com/jordanLswartz
н
Оригинал