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.