Как устроена передача сообщений в gRPC
Что проверяют
Понимаете ли вы, что происходит ниже сгенерированного кода: как вызов метода превращается в HTTP/2-стрим и байты на проводе. Следом обычно спрашивают про дедлайны, метаданные и коды ошибок.
Как отвечать
- контракт: сервис и сообщения описываются в
.proto, из негоprotocс плагинамиprotoc-gen-goиprotoc-gen-go-grpc(илиbuf generate) генерирует типы, клиент и интерфейс сервера; - транспорт: каждый вызов это отдельный стрим внутри одного HTTP/2-соединения. Запрос идёт как
POSTна путь/package.Service/Methodсcontent-type: application/grpc, метаданные передаются заголовками; - кадрирование: перед каждым сообщением 5 байт, флаг сжатия и длина в 4 байта, дальше protobuf. Статус (
grpc-status,grpc-message) приходит в трейлерах, поэтому ошибка возможна и после отданных сообщений; - четыре типа вызовов: unary, серверный стрим, клиентский стрим и двунаправленный. Для стримов в Go генерируются интерфейсы с
SendиRecv, а конец стрима распознаётся поio.EOF; - мультиплексирование: параллельные вызовы делят одно TCP-соединение, у стримов и соединения свои окна flow control.
В Go покажите работу с контекстом. Дедлайн задаётся через context.WithTimeout, уезжает на сервер заголовком grpc-timeout, и сервер видит его в ctx. Ошибки возвращаются через пакет status с кодами из codes, например codes.NotFound. Метаданные читаются через metadata.FromIncomingContext. Входящее сообщение по умолчанию ограничено 4 МБ, лимит поднимают опцией grpc.MaxRecvMsgSize на сервере и grpc.MaxCallRecvMsgSize на клиенте. Клиент создаётся через grpc.NewClient, grpc.Dial помечен устаревшим.
Где спотыкаются
Объясняют скорость только бинарным форматом. Не меньше значат переиспользование соединения и мультиплексирование. И нативного gRPC в браузере нет, там нужен gRPC-Web или прокси.
Не ставят дедлайн на клиенте. Зависший сервер держит горутину и стрим сколько угодно долго.
Возвращают из хендлера fmt.Errorf. Клиент получит codes.Unknown и не отличит «не найдено» от сбоя.