+

~2006

~2006

  • 3.5 milhões de queries por dia
  • 3.5 milhões de queries por dia (em 1999)
  • 3.5 milhões de queries por dia (em 1999)

 

  • Escalabilidade vertical era insustentável

Borg

(gerenciamento de containers)

Borg

(gerenciamento de containers)

Stubby

(comunicação)

Borg

(gerenciamento de containers)

Stubby

(comunicação)

Borg

(gerenciamento de containers)

Stubby

(comunicação)

Borg

(gerenciamento de containers)

Stubby

(comunicação)

Borg

(gerenciamento de containers)

Stubby

(comunicação)

Natan Streppel

  • Software Developer @ bornlogic
  • Trabalha como dev há mais de 6 anos

AGENDA

  • gRPC

  • Protobuffers

  • gRPC & Kotlin

gRPC

 

gRPC Remote Procedure Call

Title Text

gRPC

}

Remote Procedure Call

  • Sistema de comunicação client-server                                

Remote Procedure Calls

  • Sistema de comunicação client-server

  • Cliente chama função normalmente, mas ela é executada remotamente, em outra máquina

Remote Procedure Calls

  • Sistema de comunicação client-server

  • Cliente chama função normalmente, mas ela é executada remotamente, em outra máquina

  • Tem suas origens nos anos 70, mas vem tendo um forte come-back por conta do conceito de microsserviços

Remote Procedure Calls

gRPC é um framework RPC

gRPC é um framework RPC

  • Open source (backed by Google)

gRPC é um framework RPC

  • Open source (backed by Google)
  • Utilizado por grandes players

gRPC é um framework RPC

  • Open source (backed by Google)
  • Utilizado por grandes players
  • Com ótimas features

​            "out of the box"

É uma opção ao tradicional HTTP1.1 + JSON

enquanto em soluções web HTTP você tem um endpoint

GET /user/1

usando gRPC você tem uma chamada para um método

.getUser(RequestInput)

gRPC features

HTTP/2

HTTP/2

  • Comunicação em binário (ao contrário de texto, como HTTP/1.1)

HTTP/2

  • Comunicação em binário (ao contrário de texto, como HTTP/1.1)

  • Header Compressions (HPACK)

HTTP/2

  • Comunicação em binário (ao contrário de texto, como HTTP/1.1)

  • Header Compressions (HPACK)

  • Req/Resp Multiplexing

Protocol Buffers

Protocol Buffers são um mecanismo de serialização de dados

enquanto gRPC define como a mensagem será passada...

... protobuffer define a mensagem passada por essa comunicação

(pense como sendo o JSON da interação HTTP + JSON)

Protobuffers vivem dentro de arquivos .proto

message MyMessage {
  string first_name = 1;
  bool is_validated = 2;
}

Exemplo de mensagem definida em um arquivo .proto

message MyMessage {
  string first_name = 1;
  bool is_validated = 2;
}

Exemplo de mensagem definida em um arquivo .proto

Varints

message MyMessage {
  string first_name = 1;
  bool is_validated = 2;
}

Exemplo de mensagem definida em um arquivo .proto

Varints

são a "key" do mapa "key-value"

{
  "last_name": "dasylva"
}

mensagem JSON

{
  "last_name": "dasylva"
}

mensagem JSON

}         

}         

9 bytes

 +   7 bytes

18 bytes

Protobuff

message MyMessage {
  string last_name = 2;
}

Protobuff

}         

1 byte

message MyMessage {
  string last_name = 2;
}

mensagem encodada com "dasylva" vira isso:

12 07 64 61 73 79 6c 76 61

9 bytes

message MyMessage {
  string last_name = 2;
}

mensagem encodada com "dasylva" vira isso:

12 07 64 61 73 79 6c 76 61

}         

0x12 = field 2, tipo 2 (tipo variável)

o 0x07 ao lado significa que o tamanho variável é 7

message MyMessage {
  string last_name = 2;
}

E o que fazemos com o arquivo .proto?

Protocol buffers are now Google's lingua franca for data – at time of writing, there are 306,747 different message types defined in the Google code tree across 348,952 .proto files. They're used both in RPC systems and for persistent storage of data in a variety of storage systems.

vamos definir nosso proto file!

meu_protinho.proto

syntax = "proto3";
package kotlinconf;








              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
syntax = "proto3";
package kotlinconf;

message Atendee {
    string first_name = 1;
    string last_name = 2;
    int32 meetups_atended = 3;
    bool is_cool_person = 4;
}              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
syntax = "proto3";
package kotlinconf;

message Atendee {
    string first_name = 1;
    string last_name = 2;
    int32 meetups_atended = 3;
    bool is_cool_person = 4;
}              
              
service KotlinConfService {

}              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
syntax = "proto3";
package kotlinconf;

message Atendee {
    string first_name = 1;
    string last_name = 2;
    int32 meetups_atended = 3;
    bool is_cool_person = 4;
}              
              
service KotlinConfService {
    rpc getKotlinConfAtendees() returns ();
}              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
syntax = "proto3";
package kotlinconf;

message Atendee {
    string first_name = 1;
    string last_name = 2;
    int32 meetups_atended = 3;
    bool is_cool_person = 4;
}              
              
service KotlinConfService {
    rpc getKotlinConfAtendees(Input) returns (Output);
}              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
syntax = "proto3";
package kotlinconf;

message Atendee {
    string first_name = 1;
    string last_name = 2;
    int32 meetups_atended = 3;
    bool is_cool_person = 4;
}              
              
service KotlinConfService {
    rpc getKotlinConfAtendees(Input) returns (Output);
}              
              
message Input {
    int32 year = 1;
}
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
syntax = "proto3";
package kotlinconf;

message Atendee {
    string first_name = 1;
    string last_name = 2;
    int32 meetups_atended = 3;
    bool is_cool_person = 4;
}              
              
service KotlinConfService {
    rpc getKotlinConfAtendees(Input) returns (Output);
}              
              
message Input {
    int32 year = 1;
}
              
message Output {
    Atendee atendees = 1;
}              
              
              
              
              
              
              
              
              
              
              
              
              
              
syntax = "proto3";
package kotlinconf;

message Atendee {
    string first_name = 1;
    string last_name = 2;
    int32 meetups_atended = 3;
    bool is_cool_person = 4;
}              
              
service KotlinConfService {
    rpc getKotlinConfAtendees(Input) returns (Output);
}              
              
message Input {
    int32 year = 1;
}
              
message Output {
    repeated Atendee atendees = 1;
}              
              
              
              
              
              
              
              
              
              
              
              
              
              

uff     difícil né

Agora vamos definir o nosso server

Lembram do compilador de protos?

ele se chama protoc

ele se chama protoc

protoc \
  --java_out=src/main/kotlin \
  --proto_path=src/main/proto \
  kotlinconf.proto

como resultado, temos stubs pré-gerados!

vamos criar uma classe implementando o serviço KotlinConfService

service KotlinConfService {
    rpc getKotlinConfAtendees(Input) returns (Output);
}             
class KService {}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {
  // alt enter pra dar override automático
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {
        super.getKotlinConfAtendees(request, responseObserver)
    }
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {

    }
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {
       val year = request?.year ?: getCurrentYear()
    }
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {
       val year = request?.year ?: getCurrentYear()

       // List<AtendeeEntity>
       val atendees = KConfUseCase(year)
    }
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {
       val year = request?.year ?: getCurrentYear()

       // List<AtendeeEntity>
       val atendees = KConfUseCase(year)

       val listOfAtendees = atendees.map {
            Kotlinconf.Atendee.newBuilder()
                .setFirstName(it.FirstName)
                .setLastName(it.LastName)
                .setMeetupsAtended(it.MeetupsAttended)
                .setIsCoolPerson(it.IsCool)
                .build()
        }.toList()
    }
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {
       val year = request?.year ?: getCurrentYear()

       // List<AtendeeEntity>
       val atendees = KConfUseCase(year)

       val listOfAtendees = atendees.map {
                //map entities...
        }.toList()
    }
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {
       val year = request?.year ?: getCurrentYear()

       // List<AtendeeEntity>
       val atendees = KConfUseCase(year)

       val listOfAtendees = atendees.map {
                //map entities...
        }.toList()
        
        val response = Kotlinconf
            .Output.newBuilder()
    }
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {
       val year = request?.year ?: getCurrentYear()

       // List<AtendeeEntity>
       val atendees = KConfUseCase(year)

       val listOfAtendees = atendees.map {
                //map entities...
        }.toList()
        
        val response = Kotlinconf
            .Output.newBuilder()
            .addAllAtendees(listOfAtendees)
            
    }
}
























class KService: 
	KotlinConfServiceGrpc.KotlinConfServiceImplBase() {

    override fun getKotlinConfAtendees(
        request: Kotlinconf.Input?,
        responseObserver: StreamObserver<Kotlinconf.Output>?
    ) {
       val year = request?.year ?: getCurrentYear()

       // List<AtendeeEntity>
       val atendees = KConfUseCase(year)

       val listOfAtendees = atendees.map {
                //map entities...
        }.toList()
        
        val response = Kotlinconf
            .Output.newBuilder()
            .addAllAtendees(listOfAtendees)
            
        responseObserver?.onNext(response.build())
        responseObserver?.onCompleted()
    }
}
























xuxexo, agora vamos para a main()

fun main() {

}













              
              
              
              
              
              
              
              
              
              
              
              
import io.grpc.ServerBuilder

fun main() {


    val s = ServerBuilder
}













              
              
              
              
              
              
              
              
              
              
              
              
import io.grpc.ServerBuilder

fun main() {
  
  
    val s = ServerBuilder
              .forPort(8080)

}













              
              
              
              
              
              
              
              
              
              
              
              
import io.grpc.ServerBuilder

fun main() {
    val kService = KService()

    val s = ServerBuilder
              .forPort(8080)
              .addService(kService)
              .build()

}













              
              
              
              
              
              
              
              
              
              
              
              
import io.grpc.ServerBuilder

fun main() {
    val kService = KService()

    val s = ServerBuilder
              .forPort(8080)
              .addService(kService)
              .build()

    println("starting server")
    s.start().awaitTermination()
}













              
              
              
              
              
              
              
              
              
              
              
              

server done! vamos ao client

fun main() {

}













              
              
              
              
              
              
              
              
              
              
              
              
import io.grpc.ManagedChannelBuilder

fun main() {
    var channel = ManagedChannelBuilder
        .forAddress("localhost", 8080)
        .usePlaintext()
        .build()

}













              
              
              
              
              
              
              
              
              
              
              
              
import io.grpc.ManagedChannelBuilder

fun main() {
    var channel = ManagedChannelBuilder
        .forAddress("localhost", 8080)
        .usePlaintext()
        .build()

     var stub = KotlinConfServiceGrpc
        .newBlockingStub(channel)
        
}













              
              
              
              
              
              
              
              
              
              
              
              
import io.grpc.ManagedChannelBuilder

fun main() {
    var channel = ManagedChannelBuilder
        .forAddress("localhost", 8080)
        .usePlaintext()
        .build()

     var stub = KotlinConfServiceGrpc
        .newBlockingStub(channel)
        
     val input = Kotlinconf
        .Input.newBuilder()
        .setYear(2019)
        .build()
        
     val response = stub.getKotlinConfAtendees(input)

     println("got response $response")
}













              
              
              
              
              
              
              
              
              
              
              
              

Conclusão

gRPC não é a solução para todos seus problemas

mas é uma solução robusta, industry-proven e eficiente para problemas modernos

Podemos usar gRPC quando...

ambos serviços são internos e precisam se comunicar

Podemos usar gRPC quando...

nos interessamos em grande eficiência em processamento*

*no processo de serialization e deserialization

Podemos usar gRPC quando...

nos interessamos em grande eficiência em consumo de bandwidth (mobile, anyone??)

Existem diversas libs Kotlin que ajudam a deixar o código mais Kotlin-idiomatic

E é isso. Obrigado!

Made with Slides.com