← Назад к вопросам

Что такое gRPC и чем он отличается от REST?

1.7 Middle🔥 131 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое gRPC и чем он отличается от REST?

Основная идея

gRPC (Google Remote Procedure Call) — это современный фреймворк для удалённого вызова функций между микросервисами.

REST (Representational State Transfer) — это архитектурный стиль для веб-сервисов, основанный на HTTP и работе с ресурсами.

Оба используются для коммуникации между сервисами, но подходом совершенно по-разному.

REST: HTTP + JSON

# REST клиент
response = requests.get("http://api.example.com/users/123")
user = response.json()

# REST сервер (FastAPI)
@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"id": user_id, "name": "John"}

Особенности:

  • HTTP 1.1 (текстовый протокол)
  • JSON для сериализации данных
  • Stateless (без сохранения состояния)
  • Request-response модель
  • Легко отлаживать (видно в браузере)
  • Медленнее (текстовый формат, много overhead)

gRPC: Protobuf + HTTP/2

# gRPC сервер
import grpc
from concurrent import futures
import user_pb2
import user_pb2_grpc

class UserServicer(user_pb2_grpc.UserServiceServicer):
    def GetUser(self, request, context):
        return user_pb2.User(id=request.id, name="John")

server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
user_pb2_grpc.add_UserServiceServicer_to_server(UserServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()

# gRPC клиент
import grpc
import user_pb2
import user_pb2_grpc

with grpc.insecure_channel('localhost:50051') as channel:
    stub = user_pb2_grpc.UserServiceStub(channel)
    user = stub.GetUser(user_pb2.GetUserRequest(id=123))
    print(user.name)

Особенности:

  • HTTP/2 (бинарный, мультиплексирование)
  • Protobuf для сериализации (компактный, быстрый)
  • Может быть bidirectional streaming
  • Очень быстро и эффективно
  • Сложнее отлаживать

Таблица: REST vs gRPC

ПараметрRESTgRPC
ПротоколHTTP/1.1HTTP/2
Формат данныхJSON, XMLProtobuf (бинарный)
Размер сообщенияБольшойМаленький (часто 3-10x меньше)
СкоростьМедленнееБыстрее (до 7x)
Latency~100ms~1ms
StreamingОбмен/PullBidirectional
ОтладкаЛегко (curl, postman)Сложно (нужны спец. инструменты)
БраузерДаНет (нужен gRPC-Web)
КэшированиеHTTP кэшВручную
СтандартыВезде (RESTful API)В микросервисах
Учебная криваяЛегкоСложнее

Протоколы: HTTP/1.1 vs HTTP/2

REST с HTTP/1.1:

Запрос 1 ────────────→ Ожидание
Ответ 1 ←────────────
Запрос 2 ────────────→ Ожидание
Ответ 2 ←────────────
Запрос 3 ────────────→ Ожидание
Ответ 3 ←────────────

Проблема: connection blocking (HEAD-of-LINE blocking)

gRPC с HTTP/2:

Запрос 1 ────────────→
Запрос 2 ────────────→ (одна conexion!)
Запрос 3 ────────────→
Ответ 1 ←────────────
Ответ 2 ←────────────
Ответ 3 ←────────────

Преимущество: мультиплексирование (параллельные запросы)

Protobuf vs JSON

# Protobuf определение (.proto файл)
syntax = "proto3";

message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
}

service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(Empty) returns (stream User);
}

JSON версия (REST):

{
  "id": 123,
  "name": "John",
  "email": "john@example.com"
}

(~60 байт)

Protobuf версия (gRPC):

0x0801 1217 6a047 6f686e 7217 6a067 6f686e 40... 

(~20 байт) — 3x компактнее!

Типы коммуникации gRPC

# 1. Unary (простой запрос-ответ, как REST)
stub.GetUser(request) → response

# 2. Server streaming (сервер отправляет множество ответов)
def ListUsers(request, context):
    for user in db.all_users():
        yield user  # Отправляет поток ответов

for user in stub.ListUsers(empty):
    print(user)

# 3. Client streaming (клиент отправляет поток запросов)
def UploadUsers(request_iterator, context):
    for request in request_iterator:
        db.save(request)
    return Response(saved=count)

requests = [user1, user2, user3]
response = stub.UploadUsers(iter(requests))

# 4. Bidirectional streaming (обе стороны отправляют потоки)
def Chat(request_iterator, context):
    for message in request_iterator:
        response = process_message(message)
        yield response

Практические примеры

REST: Получение пользователя

# Клиент
response = requests.get("http://api.example.com/users/123")
user = response.json()

# Сервер (FastAPI)
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    user = await db.get_user(user_id)
    return user

gRPC: Получение пользователя

# .proto файл
service UserService {
  rpc GetUser(GetUserRequest) returns (User);
}

# Сервер
class UserServicer(user_pb2_grpc.UserServiceServicer):
    async def GetUser(self, request, context):
        user = await db.get_user(request.id)
        return user

# Клиент
async with grpc.aio.secure_channel(...) as channel:
    stub = user_pb2_grpc.UserServiceStub(channel)
    user = await stub.GetUser(user_pb2.GetUserRequest(id=123))

Когда использовать что?

Используй REST когда:

  1. Публичный API для внешних клиентов

    • Легко использовать (curl, JS fetch)
    • Стандартные инструменты (Postman, Swagger)
  2. Простая архитектура

    • Несколько микросервисов
    • Низкие требования к latency
  3. Мобильный клиент

    • REST работает везде
    • gRPC требует gRPC-Web
  4. Кэширование важно

    • HTTP кэш встроен
    • gRPC требует вручную
# Пример: Публичный API
@app.get("/api/v1/products")
def get_products():
    return [...]

Используй gRPC когда:

  1. Микросервисная архитектура

    • Много сервисов общаются между собой
    • Нужна высокая производительность
  2. Высокие требования к latency

    • Real-time системы
    • Streaming данных
  3. Большие объёмы данных

    • Protobuf компактнее JSON
    • Нужен bidirectional streaming
  4. Внутренние сервисы

    • Контролируешь оба конца
    • Отладка не критична
# Пример: Внутренний микросервис
service OrderService {
  rpc CreateOrder(CreateOrderRequest) returns (Order);
  rpc WatchOrders(Empty) returns (stream Order);  # Streaming!
}

Гибридный подход

# API Gateway: REST для клиентов
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    # Но общаемся с микросервисом через gRPC
    async with grpc.aio.secure_channel(...) as channel:
        stub = user_pb2_grpc.UserServiceStub(channel)
        user = await stub.GetUser(user_pb2.GetUserRequest(id=user_id))
    return user

Это обычный паттерн: REST для внешнего API, gRPC для internal communication.

Инструменты

ЗадачаRESTgRPC
Отладкаcurl, Postmangrpcurl, Postman
Генерация кодаOpenAPI Generatorprotoc
ДокументацияSwagger/OpenAPIprotobuf comments
МониторингPrometheus (легко)Prometheus (нужна обработка)

Заключение

  • REST — универсален, простой, стандартный для публичных API
  • gRPC — быстрый, эффективный, идеален для микросервисов
  • HTTP/2 + Protobuf даёт гигантское ускорение (до 7x)
  • Streaming в gRPC мощнее, чем polling в REST
  • Гибридный подход: REST для clients, gRPC для services

Выбирай инструмент в зависимости от требований, а не следуй тренду!

Что такое gRPC и чем он отличается от REST? | PrepBro