Найти в Дзене
Nuances of programming

Удалённые вызовы процедур в Golang

Оглавление

Источник: Nuances of Programming

Что такое удалённые вызовы процедур?

Удалённый вызов процедур (RPC) — это подпрограмма в распределённых вычислениях. Реализация RPC напоминает реализацию локальных вызовов, но обычно они не идентичны. Как правило, RPC предполагает передачу параметра, имени объекта, имени функции на удалённые серверы, откуда затем на сторону клиента возвращаются обработанные результаты (запрос-ответ). RPC осуществляется с использованием протоколов TCP, UDP или HTTP.

-2

В Golang существуют три типа реализаций, а именно:

  • net/rpc
  • net/rpc/jsonrpc
  • gRPC

net/rpc

Официальная документация Golang в пакете net/rpc использует encoding/gob в качестве методов кодирования или декодирования, поддерживающих протоколы TCP или HTTP. Но gob используется только в Golang, поэтому поддерживает лишь те серверы и взаимодействия на стороне клиента, которые написаны на Golang. Вот пример net/rpc на стороне сервера:

-3

Примечательно, что функция GetLine добавляется к Listener. Она вернёт тип error, ожидая строку с какими-то данными и ответ со стороны клиента. Кроме того, функция наверняка является указателем, поэтому объявлена структура Reply для хранения соответствующих данных Data.

В функции main мы используем сначала net.ResolveTCPAddr, а затем net.ListenTCP для установки TCP-соединения, слушая порт 12345 со всех адресов. И, наконец, используем rpc.Register для регистрации соединения, которое должно прослушиваться, принимая все запросы с указанных TCP-соединений.

Пример net/rpc на стороне клиента:

-4

На стороне клиента для установления соединения с сервером и портами будет использован rpc.Dial, а это бесконечный цикл for с функцией ReadLine, которая принимает данные от портов получения. В случае возникновения обрывов на линии активируется client.Call и запускается функция GetLine. Благодаря этому процессу, reply будет сохраняться в базе данных, а мы сможем вызвать его с помощью reply.Data (по сути, это означает: что мы вводим, то и получаем на выходе). Попробуем запустить этот код:

-5

net/rpc/jsonrpc

net/rpc поддерживает только Golang, поэтому библиотека Go использует net/rpc/jsonrpc для поддержки RPC в платформах на любом языке программирования. Для реализации аналогичного приведённому выше приложения надо лишь поменять rpc.Accept в функции main().

Вот пример net/rpc/jsonrpc на стороне сервера:

-6

Теперь пример net/rpc/jsonrpc на стороне клиента:

-7

json-rpc основан на протоколе TCP и на настоящий момент не поддерживает метод HTTP. Результаты будут те же, что и в предыдущем примере:

-8

Объект JSON в запросе имеет две похожие структуры: clientRequest и serverRequest.

-9

gRPC

Тот факт, что jsonRPC может поддерживать другие языки, но не поддерживает метод HTTP, ограничивает его применение. Поэтому в эксплуатационной среде обычно используютThrift или gRPC.

gRPC — это популярная, высокопроизводительная и общедоступная RPC-платформа, созданная в Google. Она предназначена главным образом для параллельного выполнения задач современных приложений на основе стандартного протокола HTTP/2 и поддерживает такие языки, как Python, Golang и Java. Разработана в протоколе сериализации Protobuf.

Protobuf

Protobuf (сокращение от Protocol Buffers) — это всеязычный, платформенно-независимый механизм для сериализации структурированных данных в формате, похожем на XML и JSON. Легковесный и быстрый, он очень подходит для хранения данных или обмена ими в сети RPC. Первым делом устанавливаем Protobuf:

❯ brew install protobuf
❯ protoc
--version
libprotoc 3.7.1
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

Теперь пишем образец данных на основе proto3:

-10

Таким вот образом создаём файл simple.pb.go в каталоге src/simple для поддержки gRPC.

Как использовать gRPC

Сначала устанавливаем gRPC:

❯ go get -u google.golang.org/grpc

Затем импортируем src/simple в код:

-11

Здесь pb "./src/simple" импортируется пакетом. Заметим, что в названии добавляется pb.

Первым параметром функции GetLine идёт context.Context. Второй параметр — *pb.Simple-Request (запрос определён в файле .proto). Эта функция вернёт (*pb.SimpleResponse, error), где pb.SimpleResponse соответствует определению в файле .proto. С другой стороны, SimpleRequest и SimpleResponse должны обозначаться большими буквами, несмотря на то, что в файле .proto они в верблюжьем регистре.

На стороне клиента:

-12

Сначала устанавливаем соединение с помощью grpc.Dial("localhost:12345", rpc.WithInsecure()). Затем используем pb.NewSimpleClient для создания экземпляра simpleClient в формате XXXClient. (XXX определено раннее в файле .proto для значения simple в service Simple).

Для использования RPC вводится следующая команда:

reply, err := c.GetLine(context.Background(), &pb.SimpleRequest{Data: string(line)})

GetLine определяется в файле .proto ( rpc GetLine(SimpleRequest) возвращает (SimpleResponse)). Первый параметр — context.Background(). Вторым параметром идёт request. Так как строка имеет тип []byte, её надо перевести в string. Ответ reply представляет собой экземпляр SimpleReponse, который можно получить из reply.Data:

-13

Заключение

Надеюсь, что после прочтения этой статьи у вас отложилось в голове какое-то представление о RPC (удалённом вызове процедур) и трёх типах реализации в Golang. В помощь будут и примеры кода для net/rpc, net/jsonrpc и grpc. Остаётся только написать собственный код!

Читайте также:

Читайте нас в телеграмме и vk

Перевод статьи: Kingsley Tan: What Are RPCs in Golang?