Перейти к содержанию

gRPC / Protobuf

gRPC - RPC-фреймворк, построенный вокруг типизированных методов сервиса. Protocol Buffers (protobuf) используется в нём по умолчанию как язык описания интерфейса и формат сообщений, хотя эти технологии можно применять и отдельно. Они полезны, когда API нужны генерируемые контракты, компактные бинарные сообщения или потоковая передача данных.

Контракт сервиса и генерация кода

Файл .proto описывает сообщения и методы сервиса. Компилятор и плагины gRPC генерируют классы сообщений и клиентские или серверные API для выбранных языков.

syntax = "proto3";

message RobotRequest {
  string robot_id = 1;
}

message RobotStatus {
  string robot_id = 1;
  int32 battery_percent = 2;
}

service RobotService {
  rpc GetStatus(RobotRequest) returns (RobotStatus);
  rpc ObserveStatus(RobotRequest) returns (stream RobotStatus);
}

Номера идентифицируют поля protobuf в бинарном формате. Имена улучшают читаемость исходного кода, но переименование поля не меняет его бинарную идентичность. Сгенерированные типы protobuf являются моделями транспортного контракта; преобразуйте их в доменные или UI-модели, если потребности слоёв различаются.

Типы RPC

gRPC определяет четыре формы методов:

  • Unary: один запрос и один ответ.
  • Server streaming: один запрос и поток ответов.
  • Client streaming: поток запросов и один ответ.
  • Bidirectional streaming: обе стороны обмениваются независимыми потоками. В пределах каждого потока одного RPC порядок сообщений сохраняется.

В gRPC Kotlin сгенерированные корутинные клиенты могут представлять unary-вызовы как suspend-функции, а потоки - как Flow. Для потока всё равно нужны сбор с учётом жизненного цикла, отмена и явная стратегия переподключения. На транспортном уровне gRPC есть управление потоком данных, но буферизацию приложения и поведение при медленном потребителе также нужно проектировать.

Ответственность Android-клиента

Держите сгенерированный клиент и канал в слое данных и обычно переиспользуйте канал, а не создавайте его для каждого запроса. Для production настраивайте защищённый транспорт и закрывайте долгоживущие ресурсы при уничтожении их владельца.

Задавайте deadline для вызовов: иначе клиент может ждать бесконечно, в зависимости от настроек API. Отмена корутины должна передаваться RPC, но она не откатывает работу, которую сервер уже успел выполнить.

Преобразуйте статусы gRPC, например UNAUTHENTICATED, PERMISSION_DENIED, NOT_FOUND, UNAVAILABLE и DEADLINE_EXCEEDED, в ошибки приложения. Повторяйте только временные сбои и только для операций, которые безопасно выполнить повторно или которые имеют механизм идемпотентности. Экспоненциальная задержка не делает неидемпотентный вызов безопасным.

Совместимость protobuf

Развитие схемы безопасно только при соблюдении правил бинарной совместимости:

  • добавляйте поля с новыми номерами;
  • не меняйте номера полей и не переиспользуйте номер удалённого поля;
  • резервируйте номер и желательно имя удалённого поля;
  • не меняйте тип или смысл существующего поля на месте;
  • не считайте значение скалярного типа по умолчанию признаком того, что поле было передано явно - используйте присутствие поля (optional), когда различие важно;
  • оставляйте нулевое значение enum, например STATUS_UNSPECIFIED, для неизвестного или незаданного состояния.

Старые читатели обычно сохраняют или игнорируют неизвестные поля в зависимости от обработки сообщения. Поэтому в сценарии «прочитать, изменить, записать» избегайте промежуточных представлений, которые теряют неизвестные поля.

gRPC и REST

REST обычно ориентирован на ресурсы и использует человекочитаемый JSON, что удобно для публичных API и стандартных HTTP-инструментов. gRPC ориентирован на методы сервисов, обычно работает поверх HTTP/2, предоставляет сгенерированные типы и напрямую поддерживает потоки. Бинарные сообщения могут уменьшить объём данных, но реальная производительность зависит от запросов, сервера и сети. Для обычного мобильного CRUD API REST с Retrofit может быть проще; gRPC особенно уместен, когда сервер уже использует protobuf, нужны строгие межплатформенные контракты или потоковая передача данных.

Связанные темы: HTTP / REST, Retrofit / OkHttp, Основы Flow.

Источники: основные понятия gRPC, deadlines в gRPC, руководство по proto3, рекомендации protobuf.