Навигация по миру gRPC и Node.js может показаться сложной. Я надеюсь, что эта статья поможет прояснить этот туман и даст вам четкое представление об инструментах gRPC для Node.js.

Введение в gRPC

gRPC — это мощная и современная платформа RPC, обеспечивающая эффективную связь между распределенными системами, микросервисами и API. Протокол gRPC от Google должен быть простым, эффективным и гибким, что делает его отличным выбором для разработки высокопроизводительных и масштабируемых приложений.

При работе с grpc для связи используются протокольные буферы или protobuf. Protobuf — это независимый от языка формат двоичной сериализации, который обеспечивает ряд преимуществ по сравнению с другими форматами сериализации, такими как JSON или XML. Они разработаны, чтобы быть эффективными, компактными и расширяемыми, что делает их идеальным выбором для связи между распределенными системами. Protobuf даже имеют строгую типизацию, которая помогает обнаруживать ошибки, связанные с типами, на ранних этапах разработки, а их двоичный формат приводит к меньшему размеру полезной нагрузки, снижению пропускной способности и накладных расходов на обработку.

Благодаря gRPC вы получаете быструю, эффективную и компактную связь между распределенными системами благодаря волшебству Protobufs. Но это не все! gRPC также предлагает масштабируемость для обработки одновременных подключений, взаимодействие между несколькими языками программирования, надежную обработку ошибок, поддержку шаблонов потоковой связи и активное сообщество с большим количеством ресурсов и поддержки.

Использование HTTP/2

Одна из причин, по которой gRPC настолько эффективен, заключается в том, что он использует HTTP/2 в качестве основы для связи, что обеспечивает многочисленные преимущества по сравнению с традиционным HTTP/1.1, что делает gRPC идеальным выбором для современной микросервисной архитектуры и межсервисного взаимодействия, такого как

  1. Мультиплексирование: Http/2 использует мультиплексирование, при котором сервер и клиент могут отправлять данные параллельно по одному и тому же TCP-соединению, что снижает задержку.
  2. Проталкивание сервером: это означает, что сервер может проталкивать поток сообщений на клиентские заглушки через одно TCP-соединение.
  3. Сжатие заголовков: методы сжатия, которые уменьшают размер метаданных заголовка, что приводит к более эффективной связи с меньшим использованием полосы пропускания.

и другие факторы, такие как http/2, дополняющие бинарную природу protobuf и повышающие безопасность. И используя GRPC, вы по умолчанию используете все эти преимущества!

Поэтому при работе с gRPC вы определяете свои сообщения и службы в файле .proto, который служит контрактом для обмена данными между клиентом и сервером. Затем этот файл .proto используется для генерации кода на целевом языке программирования для реализации клиентских и серверных компонентов.

Теперь при работе с gRPC в Node.js (JavaScript) есть два подхода к этому:

  1. Статическая генерация. В этом методе вы компилируете свои Protobuf с помощью компилятора protoc, аналогичного другим поддерживаемым языкам, таким как Python, Go, Java и т. д. Компилятор protoc принимает ваш файл .proto в качестве входных данных и генерирует Код JavaScript, включающий классы сообщений, классы обслуживания и функции сериализации/десериализации. Затем эти сгенерированные файлы JavaScript можно импортировать в существующий код JavaScript.
  2. Динамическая генерация: этот метод, часто встречающийся в Интернете, когда люди подходят к использованию gRPC с Node.js, включает в себя определение ваших файлов Proto, как обычно, но вместо их предварительной компиляции вы загружаете код gRPC. во время выполнения. Это позволяет динамически генерировать серверные и клиентские заглушки и другие функции gRPC «на лету» по мере необходимости, обеспечивая большую гибкость и динамическое использование gRPC в Node.js без необходимости этапа компиляции во время разработки.

Статическая генерация

Буферы вашего протокола предварительно преобразуются в JavaScript с помощью компилятора ProtoC, который принимает ваши файлы .proto в качестве входных данных и генерирует код JavaScript, включающий классы сообщений и классы обслуживания для работы с gRPC. Эти файлы можно импортировать и использовать в существующем коде JavaScript.

Требуемые пакеты

При работе со статической генерацией кода вам в основном потребуются следующие две библиотеки:

  1. grpc-tools: grpc-tools — это пакет, предоставляющий инструмент интерфейса командной строки (CLI) для создания кода клиента и сервера gRPC из файлов .proto в приложениях Node.js. Инструмент, предоставляемый grpc-tools, который мы собираемся использовать, называется grpc_tools_node_protoc. Он позволяет указать входные файлы .proto, выходной каталог и другие параметры для настройки сгенерированного кода. Он позволяет создавать артефакты статического кода, такие как сервер grpc и заглушка клиента, из файла «.proto». Эти сгенерированные артефакты кода включают методы обработки сообщений gRPC на основе типов сообщений, определенных в вашем файле «.proto», что упрощает работу с gRPC в вашем приложении.
  2. google-protobuf: этот пакет предоставляет реализацию протокольных буферов JavaScript, которая используется для кодирования и декодирования сообщений протокольного буфера, используемых в качестве формата обмена данными в gRPC. Он включает функции и классы для сериализации и десериализации сообщений буфера протокола, а также другие служебные функции для работы с сообщениями буфера протокола во время выполнения в приложении gRPC. Эти две зависимости обычно используются вместе для статического создания кода gRPC и работы с ним в приложениях Node.js. grpc-tools используется для генерации клиентского и серверного кода из файлов .proto, а google-protobuf обеспечивает поддержку времени выполнения для кодирования и декодирования сообщений protobuf в сгенерированном коде.
  3. @grpc/grpc-js. Библиотека @grpc/grpc-js — это мощный инструмент, который предоставляет набор привязок JavaScript для gRPC. Он предоставляет набор клиентских и серверных библиотек, которые позволяют разработчикам создавать приложения на основе gRPC в Node.js, не полагаясь на собственные привязки C++. Он будет использоваться вместо оригинальной библиотеки grpc в Node.js из-за улучшенной совместимости при работе с gRPC в Node.js.

Чтобы скомпилировать файл буфера протокола, вы можете использовать команду ‘grpc_tools_node_protoc’ следующим образом:

grpc_tools_node_protoc --protopath <path-to-protofile> --js_out=import_style=commonjs,binary:<output-path-for-protobuf-js-module> --grpc-out=<output-path-for-grpc-js-module> <name-of-proto-file>

Аргумент —js_out с параметром import_style позволяет указать стиль импорта для созданного модуля JavaScript protobuf при использовании команды grpc_tools_node_protoc для создания статических файлов gRPC в Node.js.

Стиль импорта commonjs генерирует модули в формате CommonJS, который является системой модулей Node.js по умолчанию, совместимой со старыми скриптами JavaScript. Если import_style не указан, по умолчанию будет использоваться commonjs.

Ключевое слово binary в параметре — js_out указывает, что результирующий модуль JavaScript будет содержать сообщения в двоичном кодировании, которые более эффективны при обмене данными gRPC для больших двоичных полезных данных.

Важно отметить, что в настоящее время grpc_tools_node_protoc не поддерживает прямое создание модулей ES6. Однако, если вы работаете с TypeScript, вы можете использовать поддержку TypeScript для модулей ES6 и импортировать сгенерированные файлы .ts в свой код TypeScript.

Сгенерированные файлы

После компиляции вы получите сгенерированный код в виде двух файлов. Например, если ваш прототип называется dummy.proto, вы получите два файла, а именно: 1. dummy_pb.js и 2. dummy_grpc_pb.js, каждый из которых предоставляет разные функции.

root
├── protos
│   └── dummy.protos
├── generated
│   ├── dummy_pb.js
│   └── dummy_grpc_pb.js
├── client.js
├── server.js
└── package.json

Файл dummy_pb.js содержит код JavaScript, который представляет сгенерированные классы сообщений для типов сообщений protobuf, определенных в вашем файле dummy.proto. Он включает в себя классы, которые позволяют создавать, манипулировать и сериализовать/десериализовывать сообщения protobuf в JavaScript. Это сгенерированный модуль JavaScript protobuf.

Файл dummy_pb.js обычно включает один класс для каждого типа сообщения, определенного в файле dummy.proto. Эти классы предоставляют методы получения и установки для доступа и изменения полей сообщений protobuf, а также методы для сериализации и десериализации сообщений в двоичный формат или формат JSON и обратно.

С другой стороны, dummy_grpc_pb.js содержит код JavaScript, который представляет сгенерированные классы клиента и сервера для связи gRPC на основе определений службы в вашем фиктивном файле .proto.

Файл dummy_grpc_pb.js обычно включает один класс клиента и один класс сервера для каждой службы, определенной в вашем файле dummy.proto. Эти классы предоставляют методы для выполнения RPC от клиента к серверу, а также для обработки входящих RPC на стороне сервера. Класс клиента обычно предоставляет методы для вызова удаленных процедур, определенных в службе, а класс сервера обычно предоставляет методы обработчика для обработки входящих RPC на сервере.

Файлы dummy_pb.js и dummy_grpc_pb.js создаются на основе определений в вашем файле dummy.proto и используются в вашем Node.js. приложение для взаимодействия со службами gRPC и обмена сообщениями protobuf.

Вы импортируете эти файлы в свое приложение Node.js и используете сгенерированные классы и методы для работы с сообщениями protobuf и создания RPC поверх gRPC.

Преимущества:

Статическая генерация или предварительная обработка протофайлов — это то, как обрабатываются protobuf в других языках, таких как Go и Python. Этот метод имеет ряд преимуществ, таких как:

  • Строгая типизация. Сгенерированные классы сообщений обеспечивают безопасность типов во время обмена данными, обнаруживая ошибки, связанные с типами, на ранних этапах разработки и позволяя использовать преимущества IntelliSense.
  • Оптимизация производительности. Подход статической генерации устраняет накладные расходы на загрузку протофайлов во время выполнения и предоставляет легкодоступные оптимизированные функции сериализации и десериализации, что приводит к более быстрому обмену данными и снижению использования полосы пропускания.
  • Знакомый опыт разработки. Подход статической генерации следует шаблонам и соглашениям других реализаций gRPC, что упрощает его внедрение и интеграцию в существующие кодовые базы.

Динамическое создание

Буферы вашего протокола предварительно преобразуются в JavaScript с помощью компилятора ProtoC, который принимает ваши файлы .proto в качестве входных данных и генерирует код JavaScript, включающий классы сообщений и классы обслуживания для работы с gRPC. Эти файлы можно импортировать и использовать в существующем коде JavaScript.

Требуемые пакеты

При работе со статической генерацией кода вам в основном потребуются следующие две библиотеки:

В этом методе ваш буфер протокола загружается и анализируется во время выполнения с помощью protobuf.js, а затем создается сгенерированный. Этот подход широко используется в Интернете при работе с gRPC с использованием Nodejs. Этот подход обеспечивает большую гибкость и динамическое использование gRPC в Node.js без необходимости этапа компиляции во время разработки. Это позволяет разработчикам определять и использовать службы gRPC без дополнительных затрат на создание и поддержку статического кода, обеспечивая большую гибкость, расширяемость и простоту использования.

Следующие библиотеки помогут вам работать с динамической генерацией в вашем приложении JavaScript:

@grpc/grpc-js: @grpc/grpc-js. Это современная и многофункциональная реализация gRPC для Node.js, которая предоставляет решение для создания gRPC- основанные приложения. Это рекомендуемый и широко используемый пакет для реализации gRPC в вашем проекте JavaScript. Он будет использоваться вместо оригинальной библиотеки grpc в Node.js из-за улучшенной совместимости при работе с gRPC в Node.js.

@grpc/protoloader: это служебный пакет для загрузки прото-файлов во время выполнения в Node.js. Он предоставляет гибкий и настраиваемый способ загрузки прото-файлов, включая поддержку таких параметров, как включение путей, настраиваемые загрузчики файлов и значения по умолчанию для полей сообщений.

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

Вы можете использовать @grpc/protoloader для загрузки протофайлов во время выполнения в Node.js, указав путь к файлу или содержимое вместе с любыми желаемыми параметрами для функций loadSync() или load(). Это возвращает объект JavaScript, представляющий определение пакета, который затем может быть передан функции grpc.loadPackageDefinition() из @grpc/grpc-js для создания динамически сгенерированного объекта определения пакета, который можно использовать для выполнения вызовов RPC.

Вы можете динамически загружать свой прото-файл в свой код, используя следующий подход:

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const protoPath = './path/to/your/proto/file.proto'; // Path to your proto file
const packageDefinition = protoLoader.loadSync(protoPath, {<options>});
const proto = grpc.loadPackageDefinition(packageDefinition);

Прото-объект обычно представляет собой объект, представляющий полное определение пакета gRPC из загруженного прото-файла. Он содержит динамически генерируемые свойства и методы, соответствующие службам, методам и типам, определенным в файле proto. Сюда входят методы сериализации и десериализации для преобразования сообщений между объектами JavaScript и двоичным форматом, а также клиентские и серверные реализации для выполнения вызовов gRPC и обработки запросов gRPC.

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

Преимущества:

Этот метод работы с gRPC имеет свои преимущества, такие как:

  1. Гибкость: динамическая генерация позволяет адаптировать время выполнения к изменениям в прото-файле, не требуя перекомпиляции или повторного развертывания, что делает его подходящим для сценариев, в которых прото-файл может часто меняться или недоступен во время компиляции.
  2. Уменьшенный размер кода: генерируются только службы и методы gRPC, которые фактически используются в приложении Node.js, что приводит к меньшему объему кода по сравнению со статической генерацией, что делает приложение более эффективным и простым в управлении.

Я надеюсь, что это дает ясное представление об обоих подходах к работе с gRPC в Node.js. В следующей части этой статьи мы углубимся в проект, реализующий оба метода, и обсудим, что следует учитывать при работе с каждым из этих подходов.