lasaris         winter

school

Pokračování lekcí Rustu

dnes vás provází Lukáš Grolig

Na co se dnes podíváme?

  • Úvod do gRPC
  • Benefity
  • Protobuf
  • Debugging
  • Tonic

gRPC

high performance open source RPC framework

Benchmark z .NET

Rust vs .NET

Protocol buffer

message Person {
  string name = 1;
  int32 id = 2;
  bool has_ponycopter = 3;
}

Data jsou předávána jako message. Položkám říkáme field.

Protocol buffer

// The greeter service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

Dále máme services. To jsou akce, které můžeme provolat a vrátí nám odpověď.

Streaming

rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

Data je možné streamovat.

proto Type Notes
double
float
int32 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.
int64 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.
uint32 Uses variable-length encoding.
uint64 Uses variable-length encoding.
sint32 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.
sint64 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.
fixed32 Always four bytes. More efficient than uint32 if values are often greater than 228.
fixed64 Always eight bytes. More efficient than uint64 if values are often greater than 256.
sfixed32 Always four bytes.
sfixed64 Always eight bytes.
bool
string A string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 232.
bytes May contain any arbitrary sequence of bytes no longer than 232.

Enum

message MyMessage1 {
  enum EnumAllowingAlias {
    option allow_alias = true;
    UNKNOWN = 0;
    STARTED = 1;
    RUNNING = 1;
  }
}

Samozřejmě můžeme udělat výčet.

Repeated

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

Aneb náš starý známy list/vector

Map

message Result {
  string url = 1;
  string title = 2;
  map<int32, string> my_map = 4;
}

slovník

Poznámky

  • Auth se řeší přes metadata. Obsluha je na úrovni jazyka/platformy, kterou využíváme.
  • Ne vždy musí být gRPC rychlejší než REST.

Tonic

Cargo.toml

[dependencies]
tonic = "0.4"
prost = "0.7"
futures-core = "0.3"
futures-util = "0.3"
tokio = { version = "1.0", features = ["rt-multi-thread", "macros", "sync", "time"] }

async-stream = "0.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rand = "0.7"

[build-dependencies]
tonic-build = "0.4"

Build.rs

fn main() {
    tonic_build::compile_protos("proto/definice.proto")
        .unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e));
}

Kód serverové části

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"); // The string specified here must match the proto package name
}

Kód serverové části

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

#[tonic::async_trait]
impl Greeter for MyGreeter {
    async fn say_hello(
        &self,
        request: Request<HelloRequest>, // Accept request of type HelloRequest
    ) -> Result<Response<HelloReply>, Status> { // Return an instance of type HelloReply
        println!("Got a request: {:?}", request);

        let reply = hello_world::HelloReply {
            message: format!("Hello {}!", request.into_inner().name).into(), // We must use .into_inner() as the fields of gRPC requests and responses are private
        };

        Ok(Response::new(reply)) // Send back our formatted greeting
    }
}

Kód serverové části

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse()?;
    let greeter = MyGreeter::default();

    Server::builder()
        .add_service(GreeterServer::new(greeter))
        .serve(addr)
        .await?;

    Ok(())
}

Kód klientské části

use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;

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

Kód klientské části

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = GreeterClient::connect("http://[::1]:50051").await?;

    let request = tonic::Request::new(HelloRequest {
        name: "Tonic".into(),
    });

    let response = client.say_hello(request).await?;

    println!("RESPONSE={:?}", response);

    Ok(())
}

To je pro dnešek vše.

Dotazy?

Děkuji za pozornost  a budu se těšit na příští setkání

Made with Slides.com