Основы gRPC
Updated Jul 2026
gRPC использует Protocol Buffers (protobuf) для определения схемы и HTTP/2 для транспорта. Он распространён в микросервисных архитектурах, где сервисы нуждаются в высокопроизводительной, типобезопасной коммуникации. Как QA-инженер, вы можете тестировать gRPC реже, чем REST, но понимание его становится всё более важным.
Чем gRPC отличается от REST
| Аспект | REST | gRPC |
|---|---|---|
| Протокол | HTTP/1.1 или HTTP/2 | Только HTTP/2 |
| Формат данных | JSON (текст) | Protocol Buffers (бинарный) |
| Схема | Необязательная (OpenAPI) | Обязательная (файлы .proto) |
| Генерация кода | Необязательная | Встроенная (генерирует клиентский/серверный код) |
| Стриминг | Не нативный | Нативный (серверный, клиентский, двунаправленный) |
| Поддержка браузера | Нативная | Требуется gRPC-Web прокси |
| Коды ошибок | HTTP-коды состояния | Коды состояния gRPC (своя система) |
Protocol Buffers
Сервисы gRPC определяются в файлах .proto:
syntax = "proto3";
package user;
service UserService {
rpc GetUser(GetUserRequest) returns (UserResponse);
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
rpc CreateUser(CreateUserRequest) returns (UserResponse);
rpc UpdateUser(UpdateUserRequest) returns (UserResponse);
rpc DeleteUser(DeleteUserRequest) returns (Empty);
}
message GetUserRequest {
string id = 1;
}
message UserResponse {
string id = 1;
string name = 2;
string email = 3;
string role = 4;
string created_at = 5;
}
message ListUsersRequest {
int32 page = 1;
int32 per_page = 2;
}
message ListUsersResponse {
repeated UserResponse users = 1;
int32 total = 2;
}
Файл .proto — это контракт. И клиент, и сервер генерируют код из него, обеспечивая типобезопасность.
Исследование с grpcurl
grpcurl — это аналог curl для gRPC, необходимый для ручного исследования и отладки.
# List available services
grpcurl -plaintext localhost:50051 list
# List methods in a service
grpcurl -plaintext localhost:50051 list user.UserService
# Describe a method
grpcurl -plaintext localhost:50051 describe user.UserService.GetUser
# Call a method
grpcurl -plaintext -d '{"id": "123"}' localhost:50051 user.UserService/GetUser
# Call with headers (metadata)
grpcurl -plaintext \
-H "Authorization: Bearer token123" \
-d '{"id": "123"}' \
localhost:50051 user.UserService/GetUser
# Call without TLS (-plaintext) for local development
# Call with TLS for staging/production (omit -plaintext)
grpcurl -d '{"id": "123"}' api.staging.example.com:443 user.UserService/GetUser
Тестирование gRPC с Python
import grpc
import user_pb2
import user_pb2_grpc
@pytest.fixture(scope="session")
def grpc_channel():
channel = grpc.insecure_channel("localhost:50051")
yield channel
channel.close()
@pytest.fixture
def user_service(grpc_channel):
return user_pb2_grpc.UserServiceStub(grpc_channel)
def test_get_user(user_service):
request = user_pb2.GetUserRequest(id="123")
response = user_service.GetUser(request)
assert response.name == "Alice"
assert response.email == "alice@test.com"
def test_get_nonexistent_user(user_service):
request = user_pb2.GetUserRequest(id="nonexistent")
with pytest.raises(grpc.RpcError) as exc_info:
user_service.GetUser(request)
assert exc_info.value.code() == grpc.StatusCode.NOT_FOUND
def test_create_user(user_service):
request = user_pb2.CreateUserRequest(
name="New User",
email="new@test.com",
role="viewer"
)
response = user_service.CreateUser(request)
assert response.id != ""
assert response.name == "New User"
Коды состояния gRPC
gRPC использует собственную систему кодов состояния, а не HTTP-коды:
| Код gRPC | Значение | Эквивалент REST |
|---|---|---|
OK |
Успех | 200 |
INVALID_ARGUMENT |
Клиент отправил некорректные данные | 400 |
NOT_FOUND |
Ресурс не существует | 404 |
ALREADY_EXISTS |
Дублирование при создании | 409 |
PERMISSION_DENIED |
Недостаточные разрешения | 403 |
UNAUTHENTICATED |
Отсутствует или невалидная аутентификация | 401 |
RESOURCE_EXHAUSTED |
Ограничение частоты или квоты | 429 |
INTERNAL |
Ошибка сервера | 500 |
UNAVAILABLE |
Сервис недоступен | 503 |
DEADLINE_EXCEEDED |
Запрос превысил таймаут | 504 |
UNIMPLEMENTED |
Метод не реализован | 501 |
Стриминг
gRPC поддерживает четыре паттерна коммуникации:
| Паттерн | Описание | Случай использования |
|---|---|---|
| Унарный | Клиент отправляет один запрос, сервер отправляет один ответ | Стандартный CRUD |
| Серверный стриминг | Клиент отправляет один запрос, сервер отправляет поток ответов | Живая лента, чтение логов |
| Клиентский стриминг | Клиент отправляет поток запросов, сервер отправляет один ответ | Загрузка файлов, пакетная обработка |
| Двунаправленный | Обе стороны отправляют потоки одновременно | Чат, совместная работа в реальном времени |
Тестирование серверного стриминга
def test_server_streaming(user_service):
"""Server streams all users matching a query."""
request = user_pb2.ListUsersRequest(page=1, per_page=100)
users = []
for response in user_service.StreamUsers(request):
users.append(response)
assert len(users) > 0
assert all(hasattr(u, "name") for u in users)
Тестирование дедлайнов/таймаутов
gRPC имеет встроенное распространение дедлайнов — клиент может установить дедлайн, и если сервер не ответит вовремя, вызов завершится ошибкой.
def test_deadline_exceeded(user_service):
"""Request with very short deadline should fail."""
request = user_pb2.GetUserRequest(id="123")
with pytest.raises(grpc.RpcError) as exc_info:
# 1 microsecond deadline — guaranteed to fail
user_service.GetUser(request, timeout=0.000001)
assert exc_info.value.code() == grpc.StatusCode.DEADLINE_EXCEEDED
Практическое упражнение
- Установите grpcurl и исследуйте gRPC-сервис (используйте публичный демо или настройте локальный)
- Перечислите доступные сервисы и методы
- Сделайте унарный вызов и проинспектируйте ответ
- Напишите Python-тесты для gRPC-сервиса: успешный случай, not found, invalid argument
- Протестируйте обработку дедлайнов с очень коротким таймаутом
Ключевые выводы
- gRPC использует Protocol Buffers (бинарные, типизированные) вместо JSON (текстовый, нетипизированный)
- grpcurl — необходимый инструмент для ручного исследования gRPC
- gRPC имеет собственную систему кодов состояния — изучите соответствия HTTP-кодам
- Тестируйте стриминг (серверный, клиентский, двунаправленный), когда сервис его поддерживает
- Распространение дедлайнов встроено — тестируйте поведение при таймаутах
- Файл
.proto— источник истины для контракта API