gRPC Часть №1 — .NET C# и Google Protobuff. Знакомство.
Так исторически сложилось, что на текущей моей работе весь стек бекенда состоял изначально из GoLang и .NET. Так начинался наш проект, к слову, абсолютно для меня экспериментальный — новый виток карьеры (в профессиональном плане). До этого момента я был полностью и целиком desktop-разработчиком под Windows (а ещё до этого десктоп QT и Linux). Я не особо любил писать Web, но судьба иронична 🙂 Так вот, однажды встал вопрос поддержания транспортного уровня между нашими сервисами и в тот момент моему полностью .NET-ориентированному восприятию предстал gRPC.
gRPC — это высопроизводительный протокол для вызова удалённых процедур (собственно, аббревиатура RPC — remote procedure call), созданный компанией Google. Задачей данной технологии является взаимодействие вашего кода с каким-либо другим, находящимся в другом адресном пространстве, сервисом. Это инкапсуляция функциональных частей некоторых сервисов, доступных по сети. Кроме непосредственного исполнения бизнес логики, RPC подразумевает автоматическую сериализацию и мапинг ответов в ваши объекты\классы, что делает работу поистине удобной. На транспортном уровне OSI gRPC «стоит» на TCP и на прикладном уровне ходит по HTTP/2. Наиболее близкие и сходные технологии, нативные для .NET — это .NET Remoting и, пришедшая ему на смену, WCF (Windows Communication Foundation).
К слову, разница с WCF у gRPC есть кардинальная, но только на низком уровне. Во-первых, в gRPC не используется SOAP. Во-вторых, это открытый Open Source проект и значит существует возможность связывать мультиязычные системы (Python, PHP, GoLang, C++ и многие другие), а не только языки из .NET стека. Способ сериализации бинарный (против XML/JSON), что даёт ощутимый прирост по скорости. Также сама генерация кодовой базы разная — у gRPC для этого требуются специальные текстовые .proto файлы, содержащие сигнатуры методов (своеобразный Interface), в отличии от WCF — где контрактом общения служит, как правило, скомпилированная единая Class Library DLL-библиотека.
Вот небольшой простенький пример .proto-файла (с именем addressbook.proto), который приводят сами Google:
syntax = "proto3"; package tutorial; message Person { string name = 1; int32 id = 2; // Уникальный числовой идентификатор человека string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; } // Адресная книга message AddressBook { repeated Person people = 1; }
Это очень простой, кроссплатформенный и мультиязычный способ организовать транспортный канал связи между вашими приложениями. Как можно заметить — это строготипизированный подход. Есть возможность организовывать вложенность типов, создание списков (Enum), массивов и многое другое. Каждое поле помечается строчкой с номером (= 1
, = 2
etc.) — это маркеры, которые служат для уникальной идентификации этих полей в бинарной кодировке. Поля, помеченные repeated
— служает своеобразными динамическими массивами.
Конечно, это только незначительная верхушка айсберга и далека от полного описания прото-файлов. Это очень простой пример. За более глубинными понятиями необходимо засучить рукава и идти в специализированную документацию (хотя, возможно, я опишу всё это отдельным постом).
Итак, теперь у нас есть proto-файл. Нам необходимо сгенерировать по нему кодовую базу. Для этого необходимо использовать специальную утилиту protoc (здесь) — это консольная утилита, которая может взять ваш файл(ы) и создать в вашем проекте все необходимые .cs-файлы. Перед генерацией я бы рекомендовал создать отдельный Class Library проект, чтобы, во-первых, получить переиспользование и, во-вторых, вынести ответственность за транспорт в отдельную зависимость. Генерировать можно так:
protoc -I=$SRC_DIR --csharp_out=$DST_DIR $SRC_DIR/addressbook.proto --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe
На выходе мы получим в нашей указанной папке набор из двух .cs файлов с вашим указанным именем Package.cs и PackageGrpc.cs. Также весь наш код будет определён в namespace, который будет равен строчке package
из протофайла. Если вам необходимо использовать какой-либо специализированный namespace, то можно добавить в протофайл следующую строку, явноуказывающую пространство имён:
option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
Итак, будем считать знакомство состоявшимся. Мы немного узнали о gRPC, научились генерировать proto-файлы и добавлять в собственный проект код. В следующих частях мы создадим рабочие проекты клиента и сервера, демонстрирующие какую-либо рабочую и полезную функциональность.