Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Тема
Описание
Доп.

RPC

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

Примеры:

  • gRPC (от Google, поверх HTTP/2 + Protocol Buffers)
  • JSON-RPC (часто в вебе и блокчейн-системах)
  • Cap’n Proto RPC
  • Thrift

Популярные библиотеки RPC в Rust

  • tonic (gRPC)
  • tarpc
  • jsonrpsee (JSON-RPC)

gRPC_example

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

  • gRPC (tonic): микросервисы, высокая производительность, межъязыковое взаимодействие.
  • tarpc: если хочется полностью "rust-native" решения без protobuf.
  • jsonrpsee: когда нужен JSON-RPC (web3, блокчейны, интеграции с JS/Python).
  • Cap’n Proto RPC: если важна скорость и минимальная сериализация.

Система обмена сообщениями gRPC использует вместо JSON бинарный формат Protobuf, благодаря чему размер сообщений становится меньше и увеличивается пропускная способность — скорость передачи в конечном итоге возрастает в 7-10 раз.

Микросервисы

Все чаще крупные проекты переходят на микросервисную архитектуру, все большее число компаний принимают gRPC в качестве стандарта передачи данных вместо REST API.

Клиент вызывает удаленную процедуру, сериализует параметры и дополнительную информацию в сообщении, после чего шлет сообщение на сервер. Приняв данные, сервер производит их десериализацию, выполняет запрошенную операцию и шлет результат обратно клиенту.

Мощности компьютера нельзя увеличивать до бесконечности и в какой-то момент достигается потолок, ограничивающий вертикальное масштабирование проекта. В качестве решения этой проблемы используют деление монолитного приложения на отдельные, небольшие, слабо связанные маленькие приложения — микросервисы. Каждый такой микросервис – это автономное приложение. Микросервисы общаются друг с другом и, взаимодействуют, выполняя функции итогового приложения. Если в монолитной архитектуре пользователь обращается к приложению и получает ответ, то, в случае с микросервисной архитектурой он обращается к микросервису. Этот микросервис, в свою очередь, обращается к другому микросервису, тот, например, может обратиться к третьему микросервису или к базе данных и т.д.

Микросервисы обмениваются информацией посредством вызовов их REST API. Неудобство REST API состоит в том, что формат данных, используемый для пересылки данных – не бинарный, а текстовый. Такой формат удобен для визуального ознакомления с содержимым, однако, он никак не оптимизируется, не сжимается при передаче. Соответственно размер передаваемого сообщения получается большой и время на его отсылку увеличивается. Если бы данные были бинарными, мы бы могли применить к ним сжатие.

Недостаток REST API состоит в том, что транспортный протокол, применяемый для передачи данных – HTTP 1.1. Поэтому организация стриминга потоковых данных затруднена.

Система обмена сообщениями gRPC использует вместо JSON бинарный формат Protobuf, благодаря чему размер сообщений становится меньше и увеличивается пропускная способность — скорость передачи в конечном итоге возрастает в 7-10 раз. Этот формат поддерживает строгую типизацию. Бинарный формат, используемый в gRPC транслируется через протокол HTTP 2, благодаря чему скорость обмена данными (согласно отдельным тестам) увеличивается на 14%. В HTTP 2 хорошо реализованы потоки данных (можно делать запрос к серверу и получать от него поток данных по каналу клиент-сервер).

Клиент и сервер обязаны хранить один и тот же proto файл, он действует как посреднический контракт для клиента для вызова любых доступных функций с сервера.

tonic (gRPC)

  • Реализация gRPC на Rust.
  • Использует prost для сериализации Protocol Buffers.
  • Работает поверх tokio.
  • Часто применяют в микросервисах.

use tonic::{transport::Server, Request, Response, Status};
use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};

pub mod hello_world {
    tonic::include_proto!("helloworld");
}

#[derive(Default)]
pub struct MyGreeter {}

#[tonic::async_trait]
impl Greeter for MyGreeter {
    async fn say_hello(
        &self,
        request: Request,
    ) -> Result, Status> {
        let reply = HelloReply {
            message: format!("Привет {}!", request.into_inner().name),
        };
        Ok(Response::new(reply))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box> {
    Server::builder()
        .add_service(GreeterServer::new(MyGreeter::default()))
        .serve("[::1]:50051".parse()?)
        .await?;
    Ok(())
}

tarpc

  • RPC-фреймворк, написанный чисто на Rust.
  • Основан на tokio, поддерживает serde для сериализации.
  • Код более "нативный", без .proto-файлов.

use tarpc::context;
use tarpc::server::{self, incoming::Incoming};
use tarpc::serde_transport::tcp;
use tarpc::tokio_serde::formats::Json;
use tokio::net::TcpListener;

#[tarpc::service]
pub trait World {
    async fn hello(name: String) -> String;
}

#[derive(Clone)]
struct WorldServer;

#[tarpc::server]
impl World for WorldServer {
    async fn hello(self, _: context::Context, name: String) -> String {
        format!("Привет, {}!", name)
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let listener = TcpListener::bind("0.0.0.0:8080").await?;
    let server = listener
        .incoming()
        .map_ok(|s| {
            let transport = tcp::Transport::from((s, Json::default()));
            transport
        })
        .map_ok(Incoming::from)
        .try_for_each(|incoming| async move {
            incoming.respond_with(WorldServer.serve()).await?;
            Ok(())
        });
    server.await?;
    Ok(())
}

jsonrpsee (JSON-RPC)

  • Лёгкая реализация JSON-RPC для Rust.
  • Популярна в блокчейн-проектах (например, в Polkadot/Substrate).

hRPC (Human-readable RPC) — это RPC-фреймворк для Rust (и не только), который позиционирует себя как более простой и "человеческий" аналог gRPC. Он старается объединить плюсы gRPC и REST:

  • бинарный транспорт (как в gRPC),
  • но при этом простота описания API (без .proto файлов).

Основная идея: Вы пишете интерфейсы прямо в Rust (или другом языке с поддержкой hRPC), и они превращаются в RPC-сервисы, доступные через HTTP/2.

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

  • Простота — не нужны сторонние IDL-файлы (как .proto в gRPC).
  • async/await-дружелюбность (на базе tokio).
  • Поддержка codegen — можно генерировать клиенты/серверы.
  • Форматы: использует serde для сериализации (обычно JSON или CBOR).
  • Протокол поверх HTTP/2 — работает через существующую инфраструктуру (TLS, прокси).

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

  • Если не хочется возиться с .proto и protobuf.
  • Если проект Rust-only и хочется максимально нативного API.
  • Если нужна простая альтернатива gRPC, но с сохранением бинарного транспорта и строгой типизации.
  • Для микросервисов и межсервисного взаимодействия, где JSON-RPC будет слишком медленным.

Пример кода hRPC

Клиент может вызвать Greeter::hello("Alice") через HTTP/2 — и это будет похоже на обычный вызов метода.


use hrpc::prelude::*;

#[derive(hrpc::Service)]
pub trait Greeter {
    async fn hello(&self, name: String) -> String;
}

pub struct GreeterImpl;

#[hrpc::async_trait]
impl Greeter for GreeterImpl {
    async fn hello(&self, name: String) -> String {
        format!("Привет, {}!", name)
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    hrpc::serve(GreeterImpl)
        .addr("127.0.0.1:5000")
        .run()
        .await?;
    Ok(())
}

WebRTC

WebRTC — это набор протоколов и API для реального времени (Real-Time Communication):

  • обмен аудио, видео, файлами между браузерами и нативными приложениями,
  • P2P-соединения поверх UDP (с fallback на TCP),
  • встроенная поддержка NAT traversal (STUN/TURN/ICE).

Через crate webrtc-rs можно:

  • Поднять P2P-видеосвязь Rust ↔ браузер.
  • Реализовать RPC поверх DataChannel.
  • Сделать децентрализованное приложение без центрального сервера.

Основные сценарии применения WebRTC

1. Аудио- и видеозвонки

  • То, ради чего WebRTC создавался изначально.

  • Используется в:

    • Google Meet, Zoom (частично), Jitsi Meet, Slack calls.
    • Любое WebRTC-совместимое приложение может напрямую подключаться к браузеру.

Особенность: передача идёт P2P, но часто через TURN-серверы (если клиенты за NAT).

2. P2P-чаты и обмен файлами

  • WebRTC поддерживает DataChannel — двусторонний канал для передачи произвольных бинарных данных.

  • Применяется для:

    • децентрализованных мессенджеров,
    • P2P-файлообмена (например, в браузере без сервера).

3. Игры и реальное время

  • WebRTC DataChannel подходит для низколатентного P2P-гейминга.

  • Используется в:

    • браузерных играх с мультиплеером,
    • стриминге игровых кадров с низкой задержкой (например, облачный гейминг).

4. Облачные и P2P-приложения

  • WebRTC можно использовать как транспортный уровень:

    • доступ к удалённому рабочему столу (например, Chrome Remote Desktop),
    • облачные IDE (VS Code в браузере),
    • P2P-сети (например, децентрализованные видеохостинги).

Связь WebRTC и RPC

  1. Разный уровень абстракции:

    • RPC (gRPC, hRPC, tarpc и т.д.) — это способ вызова удалённых функций (обычно клиент ↔ сервер).
    • WebRTC — это канал передачи данных в реальном времени (обычно P2P).
  2. Можно совместить:

    • RPC может работать поверх WebRTC DataChannel.
    • Это даёт возможность делать P2P RPC-вызовы, минуя классическую клиент-серверную модель.
    • Такой подход используют, например, в децентрализованных приложениях (P2P мессенджеры, игры, блокчейн-сети).
  3. Rust и WebRTC:

    • Есть библиотека webrtc-rs — чистая реализация WebRTC на Rust.
    • С ней можно построить P2P-канал и поверх него реализовать свой RPC (например, через bincode или serde_json).

Пример сценария

  • Веб-браузеры или Rust-приложения устанавливают WebRTC-сессию.
  • Через DataChannel создаётся двусторонний поток сообщений.
  • Поверх него запускается RPC-фреймворк (например, hRPC или свой минималистичный).

В итоге:

  • Получаем типобезопасные вызовы методов (RPC).
  • Работает через P2P-сети и NAT (WebRTC).

Когда это актуально

  • P2P-игры на Rust (минимум задержки, нет единого сервера).
  • Децентрализованные чаты/видеозвонки.
  • Блокчейн-клиенты (P2P-синхронизация).
  • Когда RPC нужен, но без центрального сервера.