Типы RPC в gRPC
Одно из ключевых преимуществ gRPC — это гибкость модели обмена данными.
REST традиционно работает в стиле “один запрос — один ответ”.
gRPC, в отличие от него, поддерживает четыре типа взаимодействия, и каждый из них решает свою задачу.
1. Unary RPC (один запрос — один ответ)
Это самый простой и самый распространённый тип — аналог классического REST-вызова.
Клиент отправляет один запрос, сервер обрабатывает его и возвращает один ответ.
Клиент → (один запрос) → Сервер
Сервер → (один ответ) → Клиент
Пример .proto
Сервер (Java)
Клиент
Где применяется:
CRUD-операции (создание, получение, обновление, удаление).
Любые точечные вызовы, где не требуется поток данных.
По сути: это "REST, но бинарный, типобезопасный и в 10 раз быстрее".
2. Server Streaming RPC (поток ответов от сервера)
В этом типе клиент делает один запрос, а сервер возвращает несколько ответов последовательно — поток сообщений.
Клиент → (один запрос) → Сервер
Сервер → (много ответов в потоке) → Клиент
Сеанс продолжается, пока сервер не закончит отправку данных.
Пример .proto
Сервер (Java)
Клиент
Где применяется:
Поток обновлений или уведомлений.
Стриминг данных (например, список записей, логи, результаты аналитики).
Долгие вычисления, когда сервер постепенно отдаёт результаты.
Пример из реального мира:
Сервер передаёт клиенту “живой” поток котировок акций или данных из IoT-устройств.
#Java #middle #gRPC #proto
Одно из ключевых преимуществ gRPC — это гибкость модели обмена данными.
REST традиционно работает в стиле “один запрос — один ответ”.
gRPC, в отличие от него, поддерживает четыре типа взаимодействия, и каждый из них решает свою задачу.
1. Unary RPC (один запрос — один ответ)
Это самый простой и самый распространённый тип — аналог классического REST-вызова.
Клиент отправляет один запрос, сервер обрабатывает его и возвращает один ответ.
Клиент → (один запрос) → Сервер
Сервер → (один ответ) → Клиент
Пример .proto
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
}
message UserRequest {
int32 id = 1;
}
message UserResponse {
string name = 1;
int32 age = 2;
}Сервер (Java)
public class UserServiceImpl extends UserServiceGrpc.UserServiceImplBase {
@Override
public void getUser(UserRequest request, StreamObserver<UserResponse> responseObserver) {
UserResponse response = UserResponse.newBuilder()
.setName("Alice")
.setAge(30)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}Клиент
UserResponse response = stub.getUser(
UserRequest.newBuilder().setId(1).build()
);
System.out.println(response.getName());
Где применяется:
CRUD-операции (создание, получение, обновление, удаление).
Любые точечные вызовы, где не требуется поток данных.
По сути: это "REST, но бинарный, типобезопасный и в 10 раз быстрее".
2. Server Streaming RPC (поток ответов от сервера)
В этом типе клиент делает один запрос, а сервер возвращает несколько ответов последовательно — поток сообщений.
Клиент → (один запрос) → Сервер
Сервер → (много ответов в потоке) → Клиент
Сеанс продолжается, пока сервер не закончит отправку данных.
Пример .proto
service OrderService {
rpc ListOrders (OrdersRequest) returns (stream Order);
}
message OrdersRequest {
string user = 1;
}
message Order {
string id = 1;
string product = 2;
}Сервер (Java)
public class OrderServiceImpl extends OrderServiceGrpc.OrderServiceImplBase {
@Override
public void listOrders(OrdersRequest request, StreamObserver<Order> responseObserver) {
for (int i = 1; i <= 3; i++) {
Order order = Order.newBuilder()
.setId("ORD-" + i)
.setProduct("Product " + i)
.build();
responseObserver.onNext(order);
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
}
responseObserver.onCompleted();
}
}Клиент
stub.listOrders(OrdersRequest.newBuilder().setUser("Bob").build())
.forEachRemaining(order -> System.out.println(order.getProduct()));Где применяется:
Поток обновлений или уведомлений.
Стриминг данных (например, список записей, логи, результаты аналитики).
Долгие вычисления, когда сервер постепенно отдаёт результаты.
Пример из реального мира:
Сервер передаёт клиенту “живой” поток котировок акций или данных из IoT-устройств.
#Java #middle #gRPC #proto
👍2
3. Client Streaming RPC (поток запросов от клиента)
Теперь наоборот — клиент отправляет поток запросов, а сервер отвечает одним итоговым сообщением.
Клиент → (много запросов) → Сервер
Сервер → (один ответ) → Клиент
Это удобно, когда клиенту нужно собрать несколько событий или пакетов данных и отправить их вместе.
Пример .proto
Сервер (Java)
Клиент
Где применяется:
Отправка файлов по частям.
Отчёты, собираемые из нескольких частей.
Потоковое логирование от клиента на сервер.
#Java #middle #gRPC #proto
Теперь наоборот — клиент отправляет поток запросов, а сервер отвечает одним итоговым сообщением.
Клиент → (много запросов) → Сервер
Сервер → (один ответ) → Клиент
Это удобно, когда клиенту нужно собрать несколько событий или пакетов данных и отправить их вместе.
Пример .proto
service UploadService {
rpc UploadPhotos (stream PhotoChunk) returns (UploadStatus);
}
message PhotoChunk {
bytes content = 1;
}
message UploadStatus {
string message = 1;
}Сервер (Java)
public class UploadServiceImpl extends UploadServiceGrpc.UploadServiceImplBase {
@Override
public StreamObserver<PhotoChunk> uploadPhotos(StreamObserver<UploadStatus> responseObserver) {
return new StreamObserver<PhotoChunk>() {
int totalBytes = 0;
@Override
public void onNext(PhotoChunk chunk) {
totalBytes += chunk.getContent().size();
}
@Override
public void onError(Throwable t) {
System.err.println("Upload failed: " + t.getMessage());
}
@Override
public void onCompleted() {
UploadStatus status = UploadStatus.newBuilder()
.setMessage("Uploaded " + totalBytes + " bytes")
.build();
responseObserver.onNext(status);
responseObserver.onCompleted();
}
};
}
}Клиент
StreamObserver<PhotoChunk> requestObserver = asyncStub.uploadPhotos(
new StreamObserver<UploadStatus>() {
@Override
public void onNext(UploadStatus status) {
System.out.println(status.getMessage());
}
@Override
public void onError(Throwable t) {}
@Override
public void onCompleted() {}
}
);
// Отправляем несколько чанков
requestObserver.onNext(PhotoChunk.newBuilder().setContent(ByteString.copyFrom(new byte[1000])).build());
requestObserver.onNext(PhotoChunk.newBuilder().setContent(ByteString.copyFrom(new byte[500])).build());
requestObserver.onCompleted();
Где применяется:
Отправка файлов по частям.
Отчёты, собираемые из нескольких частей.
Потоковое логирование от клиента на сервер.
#Java #middle #gRPC #proto
👍2