Java for Beginner
752 subscribers
733 photos
209 videos
12 files
1.21K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Архитектура gRPC: как всё работает под капотом

gRPC — это современный фреймворк удалённого вызова процедур (RPC, Remote Procedure Call), разработанный Google. Он позволяет приложениям общаться друг с другом как будто они вызывают локальные функции, хотя на самом деле взаимодействие идёт по сети. Чтобы понять, почему gRPC так эффективен, нужно разобрать его архитектуру и то, что происходит «под капотом».

1. Концепция gRPC: RPC-модель нового поколения

RPC (Remote Procedure Call) — это подход, при котором одна программа может вызвать функцию, которая физически исполняется на другом сервере.
В классической модели RPC разработчик просто вызывает метод, а инфраструктура берёт на себя всё — упаковку данных, передачу по сети и распаковку на другой стороне.


gRPC реализует эту идею, но в современном, высокопроизводительном виде — поверх HTTP/2 и с использованием Protocol Buffers для сериализации.

2. Основные участники архитектуры

Клиент (Client)
Это программа, которая инициирует вызов удалённого метода. Она не знает деталей того, как сервер устроен внутри.
Клиент работает с client stub — это локальный объект, который выглядит как обычный класс с методами, но при вызове каждого метода на самом деле выполняется сетевое обращение к серверу.


Сервер (Server)
Это приложение, которое реализует интерфейс, описанный в .proto файле. Сервер принимает запросы от клиентов, обрабатывает их и отправляет ответы.


Client Stub и Server Stub

Что такое Stub
Stub — это «заглушка», или точнее — сгенерированный код, который связывает ваш код с gRPC-инфраструктурой.

Client Stub (клиентская заглушка) — это класс, который содержит методы, соответствующие сервисам, определённым в .proto.
Когда вы вызываете метод stub.buyCar(request), gRPC автоматически:

Сериализует объект request в бинарный формат.


Отправляет его по сети через HTTP/2.

Получает ответ, десериализует и возвращает его как обычный объект Java.

Server Stub — это абстрактный класс, который вы расширяете, чтобы реализовать свою бизнес-логику. Он автоматически принимает входящие вызовы, десериализует данные и вызывает ваш метод.


Пример:
// .proto файл
syntax = "proto3";

service CarService {
rpc BuyCar (CarRequest) returns (CarResponse);
}

message CarRequest {
string model = 1;
int32 budget = 2;
}

message CarResponse {
string status = 1;
}


После генерации protoc создаёт классы:
CarServiceGrpc.CarServiceImplBase — Server Stub

CarServiceGrpc.CarServiceBlockingStub и CarServiceGrpc.CarServiceFutureStub — Client Stubs


Реализация сервера:
public class CarServiceImpl extends CarServiceGrpc.CarServiceImplBase {
@Override
public void buyCar(CarRequest request, StreamObserver<CarResponse> responseObserver) {
String result = "You bought: " + request.getModel();
CarResponse response = CarResponse.newBuilder()
.setStatus(result)
.build();

responseObserver.onNext(response);
responseObserver.onCompleted();
}
}


Клиент:
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080)
.usePlaintext()
.build();

CarServiceGrpc.CarServiceBlockingStub stub = CarServiceGrpc.newBlockingStub(channel);

CarRequest request = CarRequest.newBuilder()
.setModel("Tesla Model 3")
.setBudget(50000)
.build();

CarResponse response = stub.buyCar(request);
System.out.println(response.getStatus());



#Java #middle #gRPC
👍2
3. Роль Protocol Buffers (protobuf)

Protocol Buffers — это бинарный формат сериализации данных, разработанный Google. Он выполняет две функции:

Описание структуры данных (через .proto файл).
Это аналог схемы JSON или XML, но строгий и типизированный.

Сериализация и десериализация (преобразование объектов в компактную бинарную форму и обратно).

Пример .proto файла не только описывает сообщения, но и определяет сервис (то есть API интерфейс).

Почему protobuf — ключевой элемент:
Он компактен: бинарный формат в несколько раз меньше JSON.
Он типобезопасен: при компиляции проверяются типы.
Он быстр: сериализация и десериализация работают на уровне байтов, без парсинга текста.


4. Как происходит сериализация и десериализация


Сериализация — это процесс превращения объекта в поток байтов для передачи по сети.
Десериализация — обратный процесс.


В gRPC:
Клиент вызывает метод stub.method(request).
request сериализуется с помощью Protocol Buffers в бинарный поток.
Поток отправляется через HTTP/2.
Сервер принимает поток, десериализует его обратно в объект CarRequest.
После обработки сервер сериализует ответ (CarResponse) и отправляет обратно.

Важно: gRPC сам управляет сериализацией. Вам не нужно ничего кодировать вручную — всё делает сгенерированный stub.


5. Что делает protoc и зачем нужны плагины

protoc — это компилятор Protocol Buffers. Он принимает .proto файл и генерирует исходный код для нужного языка.

Например:
protoc --java_out=./build/generated proto/car.proto


gRPC добавляет ещё один плагин — --grpc-java_out, который генерирует код для stub'ов.
protoc --plugin=protoc-gen-grpc-java=path/to/protoc-gen-grpc-java \
--grpc-java_out=./build/generated \
--java_out=./build/generated \
proto/car.proto


Таким образом, protoc создаёт:
Классы-сообщения (CarRequest, CarResponse)
gRPC классы (CarServiceGrpc, Stub и ImplBase)


Для каждого языка есть свой плагин:
--grpc-java_out для Java
--grpc-python_out для Python
--grpc-go_out для Go
и т. д.


Это и есть причина, почему gRPC мультиплатформенный — интерфейс описывается один раз в .proto, а код для всех языков генерируется автоматически.

6. Почему gRPC быстрее REST

gRPC построен поверх HTTP/2, а REST — чаще всего поверх HTTP/1.1. Разница принципиальна.

Ключевые причины производительности:
HTTP/2 поддерживает мультиплексирование — можно отправлять несколько запросов в одном соединении без блокировки.
Сжатие заголовков (HPACK) уменьшает накладные расходы.
Бинарная сериализация (protobuf) — меньше данных, быстрее парсинг.
Постоянное соединение — нет затрат на открытие/закрытие TCP для каждого запроса.
Streaming — можно передавать поток данных, а не ждать полного ответа (например, поток логов или большого файла).


7. Суммарно: что происходит при вызове метода в gRPC

Пошагово:
Клиент вызывает метод stub.someMethod(request).
Stub сериализует объект через protobuf.
Сериализованные данные упаковываются в HTTP/2 фрейм и отправляются на сервер.
Сервер принимает фрейм, десериализует данные.
Вызвается метод реализации (ImplBase).
Сервер формирует ответ, сериализует через protobuf.
Ответ отправляется обратно по тому же соединению.
Клиент получает и десериализует ответ.


Для разработчика — это выглядит как обычный вызов функции.
Под капотом же происходит оптимизированное сетевое взаимодействие с минимальными потерями.



#Java #middle #gRPC
👍2
Что выведет код?

import java.util.HashMap;

public class Task301025 {
public static void main(String[] args) {
HashMap<Key, String> map = new HashMap<>();

Key k1 = new Key(1);
Key k2 = new Key(1);
Key k3 = new Key(2);

map.put(k1, "first");
map.put(k2, "second");
map.put(k3, "third");

k1.value = 2;

System.out.println(map.get(k1));
System.out.println(map.get(k2));
System.out.println(map.get(k3));
System.out.println(map.size());
}

static class Key {
int value;
Key(int value) { this.value = value; }

public boolean equals(Object o) {
return o instanceof Key && ((Key) o).value == this.value;
}

public int hashCode() {
return value;
}
}
}


#Tasks
👍1