Узнайте, как создавать gRPC-серверы и подключаться к ним на примере микросервиса каталога фильмов. Мы определим контракт API с помощью Protocol Buffers, настроим gRPC-сервер на NestJS с поддержкой потоковой передачи и подключим клиентов с использованием grpcurl и .NET.
Микросервисная архитектура разбивает приложения на более мелкие, независимые службы, которые могут использовать различные технологии и взаимодействовать друг с другом для выполнения задач.
Службы обмениваются данными путем отправки сообщений или генерации событий через соединяющие их каналы. gRPC (Google Remote Procedure Call) — это фреймворк, созданный Google в 2016 году, который упрощает взаимодействие между микросервисами.
Предварительные требования
В этой статье предполагается, что вы имеете:
- Знакомство с REST или GraphQL API
- Базовые знания программирования, желательно в TypeScript
Обзор межсервисного взаимодействия
Межпроцессное взаимодействие (IPC) — это способ обмена информацией и координации задач между процессами. Когда процессы выполняются на одной машине, они используют такие методы, как передача сообщений или общая память. Когда они распределены по нескольким машинам (как в микросервисах), они общаются по сети. Если упростить, микросервисное взаимодействие — это IPC, происходящее по сети.
Независимо от того, являются ли процессы локальными или распределенными, для связи им необходимы следующие ключевые компоненты:
- Клиент/Продюсер: процесс, инициирующий связь
- Сервер/Консьюмер: процесс, принимающий связь
- Сообщение или событие: то, что передается между ними
- Канал связи: путь, по которому перемещаются данные
- Протокол: правила кодирования и декодирования сообщений
Например, когда браузер (клиент) выполняет HTTP-запрос POST для создания продукта, он устанавливает TCP-соединение с сервером. Полезная нагрузка (JSON), представляющая информацию о продукте, сериализуется и отправляется в запросе. Сервер обрабатывает ее и отправляет ответ обратно.
Микросервисы используют те же компоненты, но имеют несколько ключевых отличий:
- Шаблоны взаимодействия: микросервисы поддерживают два шаблона. Шаблон «запрос-ответ» похож на типичный HTTP-запрос, когда клиент отправляет запрос и ждет ответа. Именно его использует gRPC. Микросервисы также поддерживают обмен сообщениями на основе событий, когда клиент отправляет одно или несколько сообщений, не ожидая ответа. Сервер может обрабатывать их немедленно или позже, асинхронно.
- Сетевые механизмы: хотя HTTP является наиболее распространенным способом соединения распределенных процессов, микросервисы используют и другие механизмы. gRPC по умолчанию построен поверх HTTP. Другие варианты включают NATS, Redis, MQTT, Kafka и RabbitMQ. Некоторые из них основаны на HTTP, некоторые — нет.
gRPC простыми словами
Цель gRPC — позволить любым двум распределенным процессам обмениваться данными независимо от среды выполнения или языка программирования.
Будучи фреймворком удаленных вызовов процедур, gRPC предоставляет необходимые абстракции, которые позволяют клиенту вызывать функции на сервере так, будто они являются локальными. Он берет на себя всю сложность под капотом: управление соединениями, сериализацию, кодирование, передачу и декодирование результатов.
Вот некоторые ключевые особенности gRPC:
- Подход с приоритетом контракта: контракт представляет собой файл, определяющий функции, которые предоставляет сервер, а также их параметры и типы возвращаемых значений (в gRPC они называются типами сообщений). Сервер реализует эти функции, а клиент вызывает их по мере необходимости. Контракт также управляет кодированием и декодированием сообщений. gRPC по умолчанию использует Protocol Buffers (protobuf), но также поддерживает JSON, Thrift, Avro и FlatBuffers. Это улучшает разработку, поскольку клиентам не нужно запоминать имена эндпоинтов или парсить данные, а серверы сосредоточены только на обработке запросов и отправке ответов.
- Типобезопасность: поскольку gRPC использует контракты API, он типобезопасен и помогает обнаруживать ошибки типов на этапе компиляции, а не во время выполнения, как это делают REST API.
- Построен на базе HTTP/2: gRPC использует HTTP/2 — бинарный протокол, повышающий скорость и эффективность благодаря следующим преимуществам: Бинарные кадры: сообщения отправляются в бинарном виде, что быстрее текстовых протоколов вроде HTTP/1.1 Мультиплексирование: несколько запросов и ответов передаются по одному TCP-соединению. Сервер может расставлять приоритеты запросов и возвращать ответы в любом порядке. Это решает проблему блокировки головы очереди (head-of-line blocking) в HTTP/1.1 Сжатие заголовков: использует сжатие HPACK для более эффективной работы с заголовками и повышения производительности
- Бинарные кадры: сообщения отправляются в бинарном виде, что быстрее текстовых протоколов вроде HTTP/1.1
- Мультиплексирование: несколько запросов и ответов передаются по одному TCP-соединению. Сервер может расставлять приоритеты запросов и возвращать ответы в любом порядке. Это решает проблему блокировки головы очереди (head-of-line blocking) в HTTP/1.1
- Сжатие заголовков: использует сжатие HPACK для более эффективной работы с заголовками и повышения производительности
- Шаблон «запрос-ответ»: gRPC использует шаблон «запрос-ответ». Клиент отправляет запрос, сервер обрабатывает его и отправляет ответ обратно.
- Языковая независимость: gRPC не зависит от платформы и языка программирования, поддерживается более чем 13 языками.
Основные сценарии использования
gRPC разработан для связи между серверами, а не для подключения браузеров к серверам. JavaScript в браузере не может выполнять gRPC-вызовы напрямую, несмотря на то, что большинство браузеров поддерживают HTTP/2.
JavaScript, выполняемый в браузере, не контролирует, какой протокол HTTP используется. Он полагается на обертки API, такие как fetch и XHR, которые абстрагируют лежащий в основе протокол, и браузер управляет этим внутри себя.
Существуют такие пакеты, как grpc-web, которые позволяют вызывать gRPC-серверы из веб-приложений, но они обходят это ограничение. Они отправляют HTTP/1-запросы на настроенный вами прокси-сервер (например, Envoy), который затем преобразует эти запросы в HTTP/2 и вызывает целевой gRPC-сервер.
Короче говоря, JavaScript, выполняемый в клиентском приложении в браузере, не может напрямую делать gRPC-вызовы, потому что он не может контролировать используемый протокол HTTP, а gRPC требует HTTP/2.
Что мы будем создавать
Мы создадим простое приложение каталога фильмов, выполняющее базовые операции CRUD над фильмами. Мы будем использовать Protocol Buffers для определения контракта API, так как это механизм сериализации gRPC по умолчанию.
Вот что мы сделаем:
- Определим контракт API с помощью Protocol Buffers
- Настроим сервер NestJS, реализующий методы контракта
- Подключимся к серверу с помощью grpcurl
- Выполним подключение из приложения .NET
Шаги по настройке gRPC-сервера и подключению клиента
Теперь, когда мы понимаем, что именно мы создаем, вот шаги, которым мы будем следовать:
- Определение контракта API: мы познакомимся с Protocol Buffers как со средством определения интерфейса и сериализации в gRPC. Затем мы создадим proto-файлы, определяющие службы и методы, которые будет реализовывать сервер и которые будут вызывать клиенты.
- Создание сервера: мы используем proto-файлы для генерации серверной заглушки для NestJS. Это код, который мы будем использовать для реализации методов службы. Мы рассмотрим статический и динамический разбор proto-файлов, а также узнаем о protoc (компиляторе Protocol Buffer) и плагинах для конкретных языков.
- Создание клиентов: мы создадим клиентов для взаимодействия с сервером. Мы опубликуем документацию сервера с помощью Reflection API и продемонстрируем простое взаимодействие между сервером и клиентом.
- Добавление аутентификации: мы покажем, как клиенты могут проходить аутентификацию на уровне канала с использованием SSL-сертификатов или на уровне функций с использованием метаданных.
Protocol Buffers и файлы Proto
Protocol Buffers (protobuf) — это стандартный способ определения контракта API в gRPC. Вы используете его для определения служб, методов и сообщений в файлах с расширением .proto. Protobuf обрабатывает кодирование и декодирование сообщений, отправляемых между клиентом и сервером по каналу.
Инструмент, компилирующий файлы proto, называется protoc. Поскольку protobuf не зависит от языка программирования, вы можете использовать protoc с файлами .proto для генерации заглушек на любом языке программирования. Заглушка — это просто сгенерированный код, повторяющий контракт, определенный в файле .proto, готовый для реализации на сервере или вызова из клиента.
Когда protoc генерирует заглушку во время сборки, это называется статическим разбором. Однако вы также можете динамически разбирать файлы .proto с помощью сторонних или встроенных пакетов без генерации заглушки. Это означает, что вам не нужно устанавливать protoc.
Преимуществами динамического разбора являются более быстрая разработка с меньшим количеством инструментов и настроек. Обратной стороной является меньшее количество подсказок по типам при разработке.
Поскольку файлы proto определяют контракт API, они обычно используются совместно в разных проектах. Как правило, они хранятся в отдельном репозитории и импортируются через подмодуль. В этом руководстве мы определим их один раз и вручную скопируем в каждый проект.
Определение файла Proto
Создайте файл с именем movie_service.proto в предпочитаемом каталоге и добавьте в него следующее:
Мы определили простой файл proto в соответствии со стандартными соглашениями. Имена файлов Proto должны быть в формате lower_snake_case. Файл начинается с указания редакции 2023. Редакции — это современный подход; в более старых версиях использовались syntax = "proto2" или syntax = "proto3".
Затем мы определяем имя пакета movie. Думайте об имени пакета как о пространстве имен, в котором все объявленные здесь сообщения и службы принадлежат пакету «movie». Таким образом, полная ссылка на MovieService — movie.MovieService.
Файл proto может содержать несколько служб и сообщений. Имена сообщений и служб должны быть в формате TitleCase. У нас есть четыре типа сообщений и одна служба.
Наш MovieService имеет три RPC-метода: ListMovies, StreamMovies и SearchMovies. Каждый RPC-метод принимает входное сообщение и возвращает выходное сообщение. Имена пакета, службы и метода образуют конечную точку, вызываемую клиентом.
Например, для вызова ListMovies конечная точка выглядит так:
<server-url>/movie.MovieService/ListMovies
Чтобы понять эти RPC-методы и поддерживаемые ими шаблоны связи, давайте рассмотрим четыре шаблона связи, поддерживаемые gRPC.
Шаблоны связи в gRPC
Шаблоны связи (или модели потоковой передачи) в gRPC — это абстракции, представляющие потоки данных, передаваемые между клиентом и сервером по протоколу HTTP/2. Потоковая передача возможна благодаря возможности мультиплексирования HTTP/2.
При унарной потоковой передаче клиент отправляет запрос, а сервер возвращает ответ, подобно обычному вызову REST API по протоколу HTTP/1. ListMovies использует этот шаблон.
При потоковой передаче на стороне сервера клиент отправляет запрос, а сервер возвращает данные потоком. Используйте это, когда серверу необходимо отправить большой объем данных частями. StreamMovies использует этот шаблон.
При потоковой передаче на стороне клиента клиент передает данные на сервер, отправляя их частями, и получает один ответ. Используйте это, когда у клиента есть большие полезные нагрузки для отправки.
При двунаправленной потоковой передаче и клиент, и сервер одновременно передают данные в реальном времени. Думайте об этом как о WebSockets, но строго для связи между серверами.
Выбор шаблона связи зависит от нескольких факторов, таких как объем сообщений, возникающая задержка и частота связи.
Мы также определили типы сообщений, которые представляют полезную нагрузку, передаваемую по сети. Каждое поле имеет тип, имя и номер поля.
Например, в string poster = 4;:
- string — это тип поля (любой тип, поддерживаемый Protocol Buffers)
- poster — это имя поля
- 4 — это номер поля
Имя поля (poster) является произвольным. Вы можете выбрать его, пока оно не является ключевым словом и написано в формате snake_case. Это имя предназначено только для разработчиков для идентификации поля; оно не влияет на то, как данные отправляются по сети.
Номер поля (4) идентифицирует поле при кодировании и отправке по сети. В редакции 2023 года номера полей варьируются от 1 до 536 870 111, за исключением 19 000–19 999 (зарезервировано). Каждый номер поля должен быть уникальным в пределах своего сообщения.
Кардинальность определяет, сколько значений может содержать поле:
- Одиночное значение: содержит одну строку, например, string released = 5;
- Множественные значения: содержит массив строк, например, repeated string images = 7;
Protobuf также поддерживает карты (Maps).
Поля также могут быть скалярными или составными. Скалярные поля (например, string released = 5;) являются примитивами, которые нельзя декомпозировать дальше. Составные поля используют пользовательские типы (другие сообщения или перечисления).
Например:
Здесь items — это многозначное составное поле типа MediaItem.
Настройка сервера gRPC
Теперь давайте настроим сервер с помощью файла movie_service.proto. gRPC поддерживается многими языками программирования. Мы будем использовать TypeScript и создадим микросервис NestJS из-за его элегантной архитектуры и удобного для разработчиков подхода.
Предполагая, что у вас установлен интерфейс командной строки NestJS (CLI), откройте терминал и выполните следующую команду для настройки проекта:
Мы настроили проект NestJS под названием grpc-movie-app и установили три ключевые зависимости:
- @nestjs/microservices – фреймворк микросервисов NestJS для создания микросервисов
- @grpc/grpc-js – реализация gRPC для JavaScript и TypeScript
- @grpc/proto-loader – динамически загружает и разбирает файлы proto во время выполнения
Добавление файлов Proto
Теперь давайте переместим файлы proto в папку внутри нашего проекта. В папке grpc-movie-app выполните следующие команды:
Указанная выше команда создает папку с именем proto внутри каталога ./src нашего приложения NestJS и копирует в нее наш файл movie_service.proto.
Настройка микросервиса gRPC на NestJS
Обновите файл main.ts следующим образом:
В приведенном выше коде мы настроили микросервис с помощью createMicroservice(). Вторым параметром является объект конфигурации, который определяет, какой тип микросервиса нужно создать. Мы установили transport: Transport.GRPC для использования gRPC, а затем передали объект options для настройки нашей службы gRPC.
Наша служба прослушивает порт 4190. Используя параметр protoPath, мы можем указать столько файлов proto, сколько захотим реализовать в нашей службе. В нашем случае мы указали только один — movie_service.proto. Параметр package позволяет указать, какие пакеты в этих файлах мы хотим реализовать.
NestJS внутренне проверяет правильность путей к файлам и содержимого файлов proto. Осиннтаксические ошибки или отсутствующие имена пакетов вызывают соответствующие ошибки.
Например, если бы мы указали несуществующее имя пакета, такое как moviell, и запустили приложение, выполнив npm run start:dev, мы бы увидели ошибку вроде:
Заметка о динамическом разборе
Обратите внимание, что наше приложение NestJS может работать с proto-файлами и валидировать их без установки protoc. Пакет @grpc/proto-loader динамически анализирует .proto-файлы во время выполнения, что обеспечивает удобство разработки и упрощает интеграцию gRPC.
Необязательно: Повышение безопасности типов с помощью ts-proto
Для повышения безопасности типов и упрощения реализации контракта мы можем использовать ts-proto, плагин protoc. Protoc (компилятор protobuf) не поддерживает JavaScript/TypeScript «из коробки», поэтому существуют такие плагины, как ts-proto. Он генерирует интерфейсы для сервисов и сообщений, обеспечивает безопасность типов и помогает находить ошибки во время компиляции при работе с proto-файлами. Это особенно полезно при динамическом анализе .proto-файлов.
Чтобы использовать ts-proto, сначала установите protoc. Откройте терминал и выполните следующую команду:
Затем выполните следующую команду для установки ts-proto в папку grpc-movie-app:
После этого обновите файл package.json, добавив скрипт, который использует protoc с плагином ts-proto:
В приведенном выше коде мы добавили скрипт с именем compile:proto, который указывает protoc использовать плагин ts-proto для файла movie_service.proto и генерировать вывод TypeScript в том же каталоге, где находится proto-файл.
Поскольку ts-proto не привязан к конкретному фреймворку, нам нужно настроить его для NestJS. Мы делаем это с помощью параметра --ts_proto_opt, который принимает список опций, разделенных запятыми. Мы устанавливаем nestJs=true для поддержки NestJS, а также добавляем addGrpcMetadata=true и addNestjsRestParameter=true, чтобы включить метаданные и rest-параметры в сгенерированные интерфейсы, как показано в примере фрагмента кода ниже:
Теперь выполнение команды npm run compile:proto приведет к генерации нового файла movie_service.ts в папке proto с созданными интерфейсами TypeScript, как показано ниже.
Давайте последовательно рассмотрим содержимое сгенерированного файла movie_service.ts. Он генерирует переменные для имени пакета и типы TypeScript для соответствующих сообщений.
Он также генерирует интерфейс клиента с методами MovieService для вызова gRPC-сервера. Однако он нам не понадобится.
Сгенерированный файл также включает в себя серверный интерфейс с именем MovieServiceController, который мы реализуем. Кроме того, он генерирует декоратор MovieServiceControllerMethods(), который связывает имена методов с функцией GrpcMethod(), автоматически регистрируя их в качестве обработчиков запросов.
Обратите внимание, что имена методов и переменных класса соответствуют соглашениям TypeScript. Например, ListMovies в proto-файле превращается в listMovies в TypeScript.
Реализация методов контракта
Сначала давайте добавим демонстрационные данные о фильмах. Создайте файл с именем media-data.json в папке src и добавьте в него следующее:
Теперь создайте контроллер для реализации методов контракта:
Приведенная выше команда создает файл movie.controller.ts в папке movie. Обновите его содержимое следующим образом:
Некоторые ключевые импорты в этом фрагменте включают наши фиктивные данные из media-data.json, декораторы и интерфейсы, сгенерированные ts-proto в movie_service.ts при запуске скрипта compile:proto, а также утилиты из RxJS для потоковой передачи данных.
Декоратор MovieServiceControllerMethods() внутренне регистрирует все методы класса MovieController в качестве обработчиков gRPC-запросов. Имена методов сопоставляются с именами, определенными в пакете movie из файла movie_service.proto. Обратите внимание, что имена методов записаны в формате camelCase, а не TitleCase, как это было в proto-файле.
Для методов серверной потоковой передачи, таких как streamMovies, которые возвращают большие объемы данных, мы используем Observable. Это позволяет клиенту получать данные порциями, не перегружая сеть. При тестировании мы увидим, как клиент обрабатывает потоковые данные по сравнению с отправкой всего объема сразу.
Каждый gRPC-метод должен возвращать данные, соответствующие своему типу возвращаемого значения (при условии отсутствия ошибок). Обратите внимание, что в searchMovies мы возвращаем пустой экземпляр MediaItem по умолчанию, если фильм не найден.
Настройка клиента
gRPC поддерживается многими языками программирования, поэтому мы можем настроить клиент или сервер на нашем любимом языке. Существуют также графические интерфейсы, такие как Progress Telerik Fiddler Everywhere, а также инструменты командной строки для тестирования gRPC-серверов.
В этом разделе мы создадим клиентов двумя способами: с помощью grpcurl из терминала и консольного приложения .NET.
Использование grpcurl
grpcurl — это инструмент командной строки, похожий на curl, но предназначенный для тестирования gRPC-серверов.
Сначала давайте установим grpcurl. На macOS используйте homebrew:
Убедитесь, что gRPC-сервер NestJS запущен:
Вызов gRPC-сервера
Откройте терминал и выполните следующую команду:
Приведенная выше команда подключается к gRPC-серверу NestJS на localhost:4190 и вызывает функцию ListMovies, указывая movie.MovieService/ListMovies. Результат выводится в терминал.
Параметр -plaintext сообщает grpcurl не выполнять рукопожатие TLS, так как у сервера нет SSL-сертификата. Параметр -proto указывает путь к контракту API. Наконец, мы указываем метод для вызова, используя movie.MovieService/ListMovies.
Теперь давайте вызовем функцию SearchMovies:
Для функций, требующих параметров, используйте параметр -d для передачи данных.
Экспорт gRPC API с помощью Reflection
Обратите внимание, что вызов сервера без передачи контракта приводит к ошибке.
Протокол Reflection позволяет gRPC-серверам предоставлять свой контракт API клиентам, подобно тому, как документация Swagger работает для REST API. Это полезно при отладке, поскольку клиенты могут получить список сервисов и методов, предоставляемых сервером, и автоматически скачать .proto-файл.
Давайте обновим наш сервер, чтобы включить Reflection:
Добавление Reflection в наш gRPC-сервер NestJS
Откройте терминал и выполните следующую команду для установки пакета Reflection:
Затем обновите файл main.ts следующим образом:
Мы обновили код, чтобы включить обратный вызов onLoadPackageDefinition, который принимает функцию. Эта функция вызывается для каждого проанализированного пакета, определенного в массиве package. После того как загрузчик proto анализирует .proto-файл и генерирует определения сервисов для каждого пакета, передается объект следующего вида:
Затем этот объект передается в ReflectionService и становится доступным клиентам. Чтобы увидеть это в действии, давайте перезапустим сервер и воспользуемся grpcurl для взаимодействия с ним:
Обратите внимание, что с включенным Reflection мы теперь можем взаимодействовать с сервером без явной передачи .proto-файла.
Мы можем использовать команду list для просмотра сервисов, реализуемых gRPC-сервером. Используйте команду describe для просмотра RPC-методов, предоставляемых этим сервисом. С помощью опции -proto-out-dir вы можете скачивать .proto-файлы с сервера. В следующей команде мы скачиваем их в папку с именем output_protos, которая была создана для нас автоматически.
Добавление .NET-клиента
Мы также создадим небольшой dotnet-клиент для взаимодействия с нашим сервером. Убедитесь, что у вас установлен .NET SDK, откройте терминал и выполните следующую команду для создания базового консольного приложения:
Приведенные выше команды создают консольное приложение в папке с именем GrpcMovieClient и переходят в нее. Затем мы создаем папку Protos и копируем в нее файл movie_service.proto под именем MovieService.proto в соответствии со стандартными соглашениями об именовании C#.
Наконец, мы устанавливаем три зависимости: Grpc.Net.Client для выполнения gRPC-вызовов, Google.Protobuf для работы с сообщениями protobuf и Grpc.Tools (необязательно) для генерации заглушки клиента. В качестве альтернативы вы можете использовать protoc напрямую для генерации заглушки.
Затем давайте обновим файл GrpcMovieClient.csproj, чтобы включить proto-файл:
Элемент <Protobuf> указывает системе сборки генерировать gRPC-клиент из MovieService.proto. Атрибут GrpcServices="Client" определяет, что нам нужны клиентские заглушки, а не серверные.
Соберите проект:
Эта команда собирает все зависимости. Grpc.Tools автоматически создает папку Protos в директории obj/Debug/net10.0, содержащую сгенерированные клиентские заглушки из proto-файла.
В результате сборки создается файл MovieService.cs, содержащий код, необходимый клиенту для вызова gRPC-сервера.
Теперь давайте обновим файл program.cs следующим образом:
В приведенном выше коде мы начинаем с импорта пространств имен, которые включают основную библиотеку gRPC, библиотеку настройки соединения клиента и сгенерированную заглушку.
Затем мы создаем соединение с сервером и привязываем его к MovieService. В gRPC лучшей практикой является совместное использование одного соединения несколькими клиентами, а не создание нового соединения для каждого клиента.
Затем мы вызываем каждый метод MovieService и выводим результат. В коде показано, как вызывать ListMovies (возвращает все фильмы), SearchMovies (находит определенный фильм) и StreamMovies (передает фильмы по одному).
Чтобы запустить приложение:
Метаданные (или заголовки) в gRPC представляют собой пары ключ-значение, которые клиенты включают в запросы, а серверы — в ответы. К частым сценариям использования относятся добавление информации об аутентификации и авторизации, а также хранение информации, которая иначе увеличила бы тело protobuf-сообщения.
Давайте посмотрим, как добавлять метаданные на сервере и читать их на клиенте. Обновите метод streamMovies в файле movie.controller.ts следующим образом:
Каждый метод gRPC принимает три параметра. Второй представляет метаданные, отправленные клиентом. Поскольку мы хотим отправить метаданные обратно клиенту, мы импортировали класс Metadata и создали его экземпляр. Мы добавили пару ключ-значение (token: secret-token) с помощью метода set(). Экземпляр Metadata содержит методы для добавления, обновления и извлечения записей.
Теперь давайте обновим .NET-клиент для чтения и отображения возвращенных метаданных. Обновите файл program.cs следующим образом:
Запустите dotnet run, чтобы увидеть вывод:
Аналогично, выполнив команду с помощью grpcurl, мы получаем заголовок, показанный ниже.
Мы включили опцию -v (подробно), чтобы получить полную информацию об отклике. Обратите внимание на заголовок token в отклике.
Краткий обзоро формата передачи данных
Мы успешно создали gRPC-сервер и подключили клиентов с помощью grpcurl и платформы .NET. Ранее мы подчеркивали роль Protocol Buffers в кодировании и декодировании сообщений. В этом разделе мы рассмотрим формат передачи данных и то, как сообщения кодируются перед отправкой по сети.
Например, когда мы вызываем SearchMovies с полезной нагрузкой FindMovieRequest, сообщение выглядит следующим образом:
Сообщение может содержать несколько полей. Вот как оно кодируется и передается по сети после установления соединения между клиентом и сервером:
Порядок полей не имеет значения при кодировании или декодировании. Тем не менее, по возможности важно использовать меньшие номера полей (1–15), так как они занимают меньше места при передаче по сети.












