Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
gRPC: Remote Procedure Call
Что такое gRPC
gRPC (gRPC Remote Procedure Call) — это **высокопроизводительный RPC фреймворк**, разработанный Google. Позволяет вызывать методы другого сервера так, как будто это локальные методы.
Зачем это нужно
Проблема REST API:
- Текст (JSON) — медленнее, чем бинарный формат
- HTTP/1.1 — не оптимален для микросервисов
- Много overhead'а на сериализацию/десериализацию
- Нет встроенного потокового взаимодействия
Решение: gRPC
- Использует Protocol Buffers (бинарный формат) — 3-10x быстрее JSON
- Использует HTTP/2 — множественные потоки в одном соединении
- Двусторонняя потоковая передача (streaming)
- Встроенная поддержка load balancing
- Меньше latency
Установка
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.53.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.53.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.53.0</version>
</dependency>
Protocol Buffers (protobuf)
Definition файл user.proto:
syntax = "proto3";
package com.example.grpc;
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
message GetUserRequest {
int32 user_id = 1;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
service UserService {
// Unary RPC: один запрос, один ответ
rpc GetUser(GetUserRequest) returns (User) {}
// Server streaming: один запрос, поток ответов
rpc ListUsers(google.protobuf.Empty) returns (stream User) {}
// Client streaming: поток запросов, один ответ
rpc CreateUsers(stream CreateUserRequest) returns (google.protobuf.Empty) {}
// Bidirectional streaming: два потока одновременно
rpc Chat(stream Message) returns (stream Message) {}
}
Компилирование:
# Maven
mvn compile
# Gradle
gradle build
Генерируется код:
UserProto.java— сообщенияUserServiceGrpc.java— service interface
Реализация сервера
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
public class UserServiceImpl extends UserServiceGrpc.UserServiceImplBase {
// Unary RPC
@Override
public void getUser(UserOuterClass.GetUserRequest request,
StreamObserver<UserOuterClass.User> responseObserver) {
int userId = request.getUserId();
// Получить пользователя из БД
UserOuterClass.User user = UserOuterClass.User.newBuilder()
.setId(userId)
.setName("John Doe")
.setEmail("john@example.com")
.build();
responseObserver.onNext(user);
responseObserver.onCompleted();
}
// Server streaming
@Override
public void listUsers(com.google.protobuf.Empty request,
StreamObserver<UserOuterClass.User> responseObserver) {
// Отправить несколько пользователей
for (int i = 1; i <= 5; i++) {
UserOuterClass.User user = UserOuterClass.User.newBuilder()
.setId(i)
.setName("User " + i)
.setEmail("user" + i + "@example.com")
.build();
responseObserver.onNext(user);
}
responseObserver.onCompleted();
}
// Client streaming
@Override
public StreamObserver<UserOuterClass.CreateUserRequest> createUsers(
StreamObserver<com.google.protobuf.Empty> responseObserver) {
return new StreamObserver<UserOuterClass.CreateUserRequest>() {
@Override
public void onNext(UserOuterClass.CreateUserRequest request) {
// Получение каждого запроса от клиента
System.out.println("Creating user: " + request.getName());
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onCompleted() {
responseObserver.onNext(com.google.protobuf.Empty.getDefaultInstance());
responseObserver.onCompleted();
}
};
}
}
// Запуск сервера
public class GrpcServer {
public static void main(String[] args) throws Exception {
Server server = ServerBuilder.forPort(50051)
.addService(new UserServiceImpl())
.build();
server.start();
System.out.println("Server started on port 50051");
server.awaitTermination();
}
}
Клиент
import io.grpc.Channel;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class GrpcClient {
public static void main(String[] args) throws InterruptedException {
// Подключение к серверу
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 50051)
.usePlaintext()
.build();
UserServiceGrpc.UserServiceBlockingStub stub =
UserServiceGrpc.newBlockingStub(channel);
// Unary RPC
UserOuterClass.GetUserRequest request =
UserOuterClass.GetUserRequest.newBuilder()
.setUserId(1)
.build();
UserOuterClass.User user = stub.getUser(request);
System.out.println("User: " + user.getName() + " (" + user.getEmail() + ")");
// Server streaming
Iterator<UserOuterClass.User> users = stub.listUsers(
com.google.protobuf.Empty.getDefaultInstance()
);
while (users.hasNext()) {
UserOuterClass.User u = users.next();
System.out.println("User: " + u.getName());
}
// Client streaming
StreamObserver<UserOuterClass.CreateUserRequest> requestObserver =
stub.createUsers(new StreamObserver<com.google.protobuf.Empty>() {
@Override
public void onNext(com.google.protobuf.Empty value) {}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onCompleted() {
System.out.println("All users created");
}
});
requestObserver.onNext(UserOuterClass.CreateUserRequest.newBuilder()
.setName("Alice")
.setEmail("alice@example.com")
.build());
requestObserver.onNext(UserOuterClass.CreateUserRequest.newBuilder()
.setName("Bob")
.setEmail("bob@example.com")
.build());
requestObserver.onCompleted();
// Завершение
channel.shutdown();
channel.awaitTermination(10, java.util.concurrent.TimeUnit.SECONDS);
}
}
Асинхронный клиент
public class AsyncGrpcClient {
public static void main(String[] args) {
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 50051)
.usePlaintext()
.build();
// Асинхронный stub
UserServiceGrpc.UserServiceStub stub =
UserServiceGrpc.newStub(channel);
UserOuterClass.GetUserRequest request =
UserOuterClass.GetUserRequest.newBuilder()
.setUserId(1)
.build();
stub.getUser(request, new StreamObserver<UserOuterClass.User>() {
@Override
public void onNext(UserOuterClass.User user) {
System.out.println("Received: " + user.getName());
}
@Override
public void onError(Throwable t) {
System.err.println("Error: " + t.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Call completed");
}
});
// Не завершай сразу
try {
Thread.sleep(5000);
} catch (InterruptedException e) {}
channel.shutdown();
}
}
Spring Boot интеграция
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>2.14.0.RELEASE</version>
</dependency>
@GrpcService
public class UserServiceGrpcImpl extends UserServiceGrpc.UserServiceImplBase {
@Autowired
private UserRepository userRepository;
@Override
public void getUser(UserOuterClass.GetUserRequest request,
StreamObserver<UserOuterClass.User> responseObserver) {
User dbUser = userRepository.findById(request.getUserId()).orElse(null);
if (dbUser != null) {
UserOuterClass.User grpcUser = UserOuterClass.User.newBuilder()
.setId(dbUser.getId())
.setName(dbUser.getName())
.setEmail(dbUser.getEmail())
.build();
responseObserver.onNext(grpcUser);
}
responseObserver.onCompleted();
}
}
Конфигурация:
grpc.server.port=50051
Когда использовать gRPC
- Микросервисная архитектура — общение между сервисами
- Высокая нагрузка — нужна максимальная производительность
- Real-time приложения — streaming данные
- IoT и мобильные — мало bandwidth
- Внутренний API — не для публичных API
Преимущества vs REST
┌────────────────┬──────────┬─────────┐
│ Параметр │ gRPC │ REST │
├────────────────┼──────────┼─────────┤
│ Сериализация │ 3-10x │ 1x │
│ Размер │ 7x ↓ │ - │
│ Latency │ 7x ↓ │ - │
│ Streaming │ ✓ │ ✗ │
│ Простота │ Средняя │ Высокая │
│ Browser │ ✗ │ ✓ │
└────────────────┴──────────┴─────────┘
Недостатки
- Не работает напрямую в browser'е (нужен gateway)
- Крутая кривая обучения
- Отладка сложнее, чем REST
- Protocol Buffers нужно учить
- Менее популярен чем REST
Инструменты для тестирования
# Evans — интерактивный gRPC клиент
evans -r localhost:50051
# grpcurl — аналог curl для gRPC
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext -d '{"user_id": 1}' localhost:50051 com.example.grpc.UserService.GetUser
Вывод
gRPC — это отличный выбор для микросервисов и высоконагруженных систем, но не замена REST. Для публичных API лучше REST, для внутреннего взаимодействия — gRPC.