gRPC в C#: когда REST — прошлый век, а HTTP/1.1 — тормоз
Представьте, что вы — пилот Формулы-1. Ваш болид способен разгоняться до 380 км/ч, но вы едете по городским пробкам. Бессмысленно, правда? Примерно так же часто используют gRPC в C# — мощнейший инструмент для межсервисного взаимодействия — там, где хватило бы обычного REST API. А потом удивляются: «почему сложно отлаживать, зачем столько кода?».
Давайте разберёмся, когда использовать gRPC действительно оправдано, а когда лучше остаться на проверенном HTTP/1.1. Спойлер: gRPC — это не серебряная пуля. Это ракетный ускоритель для правильных задач.
Что такое gRPC и почему C# — идеальный полигон
gRPC (Google Remote Procedure Call) — это фреймворк для удалённого вызова процедур, построенный на HTTP/2 и Protocol Buffers. Вместо громоздкого JSON — компактный бинарный формат. Вместо одного запрос-ответ — полноценные стримы, мультиплексирование и двусторонняя связь.
Почему C# gRPC — это бомба? Потому что .NET Core с самого начала затачивали под высоконагруженные микросервисы. Асинхронность, Span<T>, низкий уровень аллокаций — всё это делает связку C# + gRPC одной из самых производительных в индустрии.
// Пример простого .proto файла
syntax = "proto3";
service OrderService {
rpc GetOrder (OrderRequest) returns (OrderResponse);
rpc SubscribeOrders (OrderFilter) returns (stream OrderUpdate);
}
message OrderRequest {
string order_id = 1;
}
message OrderResponse {
string id = 1;
double total = 2;
repeated string items = 3;
}
После генерации кода через protoc или пакет Grpc.Tools вы получите полноценный C# класс, который можно использовать как обычный метод.
Когда gRPC в C# реально нужен? 5 железобетонных сценариев
1. Микросервисы с высокой нагрузкой (1000+ rps)
Если ваша система обрабатывает тысячи запросов в секунду, каждый лишний килобайт в JSON и каждый дополнительный RTT (round-trip time) превращаются в потерю денег. gRPC в C# даёт выигрыш в скорости до 7-10 раз по сравнению с REST/JSON за счёт:
- Бинарной сериализации (Protobuf — в 3-5 раз компактнее JSON)
- HTTP/2 мультиплексирования (один TCP-канал на множество запросов)
- Отсутствия накладных расходов на парсинг заголовков
2. Стриминг данных в реальном времени
Вам нужно передавать котировки акций, логи, телеметрию IoT-датчиков или обновления UI? Streaming gRPC C# — ваш выбор. Поддерживаются четыре типа стримов:
- Unary — классический запрос-ответ
- Server streaming — сервер шлёт данные клиенту
- Client streaming — клиент шлёт пачку данных серверу
- Bidirectional streaming — двусторонний непрерывный обмен
// Серверная часть bidirectional streaming
public override async Task SubscribeOrders(
IAsyncStreamReader<OrderFilter> requestStream,
IServerStreamWriter<OrderUpdate> responseStream,
ServerCallContext context)
{
await foreach (var filter in requestStream.ReadAllAsync())
{
var update = new OrderUpdate
{
OrderId = filter.OrderId,
Status = "Shipped"
};
await responseStream.WriteAsync(update);
}
}
3. Внутренние микросервисы одной команды
gRPC плохо подходит для публичных API (слабая поддержка браузеров, сложный дебаг). Но внутри кластера — это идеальный транспорт. Если вы контролируете и клиент, и сервер, gRPC на C# даёт:
- Строгую типизацию через .proto контракты
- Автоматическую генерацию клиентов
- Поддержку graceful shutdown и deadline propagation
4. Мобильные приложения с плохим каналом
Мобильный интернет — это боль: высокий пинг, частые обрывы, маленький bandwidth. gRPC в C# сжимает данные в 4-5 раз сильнее JSON. А HTTP/2 позволяет держать одно соединение, а не открывать новое под каждый запрос. Для мобильных SDK на Xamarin или .NET MAUI — это спасение.
5. Полиглотные системы (C# + Go + Python + ...)
gRPC — кроссплатформенный. Вы пишете .proto файл один раз, а генерируете клиенты на C#, Go, Python, Java, Rust. Это идеально, когда ваш бэкенд на C#, а ML-сервисы на Python. Protobuf C# гарантирует, что структуры данных совпадут на всех языках.
Когда gRPC — это overkill? Спойлер: чаще, чем кажется
Не используйте gRPC в C#, если:
- Ваш API публичный. Браузеры не поддерживают gRPC напрямую (нужен gRPC-web, который теряет часть преимуществ). REST + JSON — стандарт де-факто для внешних интеграций.
- У вас 2-3 микросервиса с нагрузкой 50 rps. Настройка gRPC, тулинг, дебаг — овчинка выделки не стоит. Обычный WebAPI на ASP.NET Core справится.
- Вам нужна человекочитаемость. JSON можно посмотреть в браузере, curl, Postman. Для gRPC нужны gRPCurl, BloomRPC или GUI-клиенты. Это дополнительный барьер.
- Вы используете legacy .NET Framework. gRPC полноценно поддерживается только на .NET Core 3.1+ и .NET 5+. На старом Framework придётся использовать Grpc.Core (устаревший пакет) с ограничениями.
Практический пример: переписываем REST-метод на gRPC в C#
Допустим, у нас есть метод получения списка заказов пользователя на REST:
// REST API
[HttpGet("users/{userId}/orders")]
public async Task<IActionResult> GetOrders(Guid userId)
{
var orders = await _db.Orders
.Where(o => o.UserId == userId)
.ToListAsync();
return Ok(orders); // JSON — 12 Kb на 100 заказов
}
Переписываем на gRPC C#:
// .proto файл
service UserService {
rpc GetUserOrders (UserOrdersRequest) returns (UserOrdersResponse);
}
message UserOrdersRequest {
string user_id = 1;
int32 page_size = 2;
int32 page_token = 3;
}
message UserOrdersResponse {