sangheee / issues

2 stars 0 forks source link

gPRC Up & Running 읽기 #5

Open sangheee opened 2 years ago

sangheee commented 2 years ago

gRPC: Up and Running (Building Cloud Native Applications with Go and Java for Docker and Kubernetes) cloud native와 MSA의 등장으로 application간의 inter-process communication technologies를 사용한 network 연결이 필요

CNCF Definition 클라우드 네이티브 기술은 조직이 퍼블릭, 프라이빗, 그리고 하이브리드 클라우드와 같은 현대적이고 동적인 환경에서 확장 가능한 애플리케이션을 개발하고 실행할 수 있게 해준다. 컨테이너, 서비스 메쉬, 마이크로서비스, 불변(Immutable) 인프라, 그리고 선언형(Declarative) API가 이러한 접근 방식의 예시들이다.

이 기술은 회복성, 관리 편의성, 가시성을 갖춘 느슨하게 결합된 시스템을 가능하게 한다. 견고한 자동화 기능을 함께 사용하면, 엔지니어는 영향이 큰 변경을 최소한의 노력으로 자주, 예측 가능하게 수행할 수 있다.

Cloud Native Computing Foundation은 벤더 중립적인 오픈 소스 프로젝트 생태계를 육성하고 유지함으로써 해당 패러다임 채택을 촉진한다. 우리 재단은 최신 기술 수준의 패턴을 대중화하여 이런 혁신을 누구나 접근 가능하도록 한다.

읽을 거리:

sangheee commented 2 years ago

Introduction to gRPC

What is gRPC
> gRPC is a modern open source high performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. (https://grpc.io/) - gRPC는 분산된 heterogeneous applications를 마치 local function call로 connect, invoke, operate, and debug할 수 있게 하는 inter-process communication technology이다. - gRPC application 개발 첫 단계는 **service interface**를 정의하는 것이다. - service interface definition: how your service can be consumed by consumers, what methods you allow the consumers to call remotely, what method parameters and message formats to use when invoking those methods, and so on. - _interface definition language_(IDL) 를 사용하여 서비스 정의 - server definition을 사용해 `server-skeleton`과 `client-stub`을 만들 수 있다. - client-stub은 서로 다른 프로그래밍 언어에 대한 low-level communication을 감추고 추상화한다. - service interface definition에서 지정한 methodsms client side에서 local function 호출만큼 쉽게 원경 호출 가능하다. ### use case of microservice implemented with gRPC image - `ProtuctInfo.proto` file에 service definition을 지정하며, 이는 server와 client의 코드를 생성하는데 사용된다. - input parameter, return type을 지정하여 _service에 노출되는 method를_ service interface definition에 정의 #### Service Definition - gRPC는 service interfae를 정의하기 위한 IDL로 [protocol buffers](https://developers.google.com/protocol-buffers)를 사용한다. - 프로토콜 버퍼는 언어에 구애받지 않고, 플랫폼 중립적이며, 확장 가능한 structued data serialization 메커니즘이다. - service interface definition은 `.proto` 확장자를 가진 일반 텍스트 파일에 지정된다. - procol buffer를 사용한 service definition 정의에는 *remote method, input/output parameters, parameter들의 type(or message format) 지정*이 포함된다. ```protobuf // ProductInfo.proto syntax = "proto3"; // protocol buffer version that we use package ecommerce; // package name to prevent name clashes between protocol message types and to genereate code service ProductInfo { // defining the service interface of a gRPC service rpc addProduct(Product) returns (ProductID); // remote method to add a product that returns the product ID as the response rpc getProduct(ProductID) returns (Product); } message Product { // definition of the message format/type of Product string id = 1; string name = 2; string description = 3; } message ProductID { string value = 1; } ``` - package에 version을 함께 지정할 수 있어 major change가 있으면 이를 인지하게 할 수 있음 - field holds unique field numbers that are used to identify your fields in the message binary format - service는 원격 호출 가능한 methods의 collection - service definition을 정의했으면 protocol buffer compiler **`protoc`**를 사용해 server-/client-side code + regular protocol buffer code(populating, serializing, retrieving your message type)를 생성할 수 있다 #### gRPC Server - gRPC server는 client call을 처리하기 위해 gRPC server를 실행 1. service definition으로 생성된 service base class service skeleton을 override하여 **service logic 구현** 2. run a gRPC server to listen for requests from clients and return the service responses ```golang // gRPC server-side implementation of ProductInfo service with Go import ( ... "context" pb "github.com/grpc-up-and-running/samples/ch02/productinfo/go/proto" "google.golang.org/grpc" ... ) // ProductInfo implementation with Go // Add product remote method func (s *server) AddProduct(ctx context.Context, in *pb.Product) ( *pb.ProductID, error) { // business logic !!!!여기에 service logic!!!!! } // Get product remote method func (s *server) GetProduct(ctx context.Context, in *pb.ProductID) ( *pb.Product, error) { // business logic !!!!여기에 service logic!!!!! } ``` ```golang // run a gRPC server func main() { lis, _ := net.Listen("tcp", port) s := grpc.NewServer() pb.RegisterProductInfoServer(s, &server{}) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } } ``` #### gRPC Client - server definition으로 생성되는 client-stub은 server와 동일한 method를 제공한다. - client stub은 이를 sever side로 가는 network call을 호출하는 remote function으로 변환한다. - gRPC service definition이 언어 종속적이지 않으므로 지원하는 모든 종류의 client/server를 생성할 수 있다. ```java // Create a channel using remote server address ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080) .usePlaintext(true) .build(); // Initialize blocking stub using the channel ProductInfoGrpc.ProductInfoBlockingStub stub = ProductInfoGrpc.newBlockingStub(channel); // Call remote method using the blocking stub StringValue productID = stub.addProduct( Product.newBuilder() .setName("Apple iPhone 11") .setDescription("Meet Apple iPhone 11." + "All-new dual-camera system with " + "Ultra Wide and Night mode.") .build()); ``` - the simple steps involved in a client-side implementation **involve setting up a connection with the remote server, attaching the client stub with that connection, and invoking the remote method using the client stub.** #### Client–Server Message Flow - on the client side - gRPC client가 gRPC service를 호출하면, client-side gRPC library는 HTTP/2를 통해 전송되는 remote procedure call protocol buffer format을 marshaling - on the server side - request unmarshaling, 각 procedure call은 protocol buffer를 사용하여 실행된다.

Evolution of Inter-Process Communication

Why gRPC

advantages of gRPC

disadvantages of gRPC

sangheee commented 2 years ago

Getting Started with gRPC

client–server communication patterns for each method invocation

image

Creating the Service Definition

Implementation

Implementing a gRPC service with Go

  1. generate the stubs for the service definition

    • create a new go module
      go mod init github.com/sangheee/grpc-test/service
    • update go.mod file with the dependencies with specific version
      
      module github.com/sangheee/grpc-test/service

    require ( github.com/gofrs/uuid v3.2.0 github.com/golang/protobuf v1.3.2 github.com/google/uuid v1.1.1 google.golang.org/grpc v1.24.0 )

    - generate client/server stubs
      - download and install latest protocol buffer version 3 compiler
      - install the gRPC library 
      ```bash
      go get -u google.golang.org/grpc
    • install the protoc plug-in for Go
      go get -u github.com/golang/protobuf/protoc-gen-go
    • generate the code
      protoc --go_out=plugins=grpc:<module_dir_path>/ecommerce ecommerce/product_info.proto 
  2. implement the business logic using the generated code

    • go module 내에 test_service.go 같은 이름의 새로운 go file 생성하고 remote method 구현

      test_service.go ```golang package main import ( "context" "errors" "log" "github.com/gofrs/uuid" pb "grpc-test/service/test" // import the package that contains generated code ) // server is used to implement test/product_info type server struct{ productMap map[string]*pb.Product } // AddProduct implements ecommerce.AddProduct func (s *server) AddProduct(ctx context.Context, in *pb.Product) (*pb.ProductID, error) { out, err := uuid.NewV4() if err != nil { return nil, status.Errorf(codes.Internal, "Error while generating Product ID", err) } in.Id = out.String() if s.productMap == nil { s.productMap = make(map[string]*pb.Product) } s.productMap[in.Id] = in return &pb.ProductID{Value: in.Id}, status.New(codes.OK, "").Err() } // GetProduct implements ecommerce.GetProduct func (s *server) GetProduct(ctx context.Context, in *pb.ProductID) (*pb.Product, error) { value, exists := s.productMap[in.Value] if exists { return value, status.New(codes.OK, "").Err() } return nil, status.Errorf(codes.NotFound, "Product does not exist.", in.Value) } ```` - `type server struct{ ` is an abstraction of the server it allows attaching service methods to the server. - both `AddProduct` and `GetProduct` method는 `Context`를 parameter로 가진다. - `Context` object는 request lifetime동안 존재하며, end user authorization token, request deadline 등의 metadata를 포함한다
    • create server that hosts the service and accepts requests from client

      server_main.go ```golang package main import ( "log" "net" pb "productinfo/service/ecommerce" "google.golang.org/grpc" ) const ( port = ":50051" ) func main() { lis, err := net.Listen("tcp", port) if err!=nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterProductInfoServer(s, &server{}) // register the newly created gRPC server by calling generated APIs log.Printf("Starting gRPC listener on port " + port) if err := s.Serve(lis); err != nil { // start listening to the incoming message on the port log.Fatalf("failed to serve: %v", err) } } ```

Implementing a gRPC client with Go

sangheee commented 2 years ago

gRPC Communication Patterns

unary RPC (simple RPC), server-side streaming, client-side streaming, and bidirectional streaming.

sangheee commented 2 years ago

gRPC: Under the Hood

RPC Flow

how a remote procedure call works over the network when the client calls remote function in the generated stub

image
  1. client process 가 generated stub의 remote function(getProduct)를 호출하면, client stub은 encoding된 message로 HTTP POST 요청을 생성한다.
    • gRPC에서 모든 요청은 HTTP POST, content-type은 application/grpc prefixed
    • 호출 함수(/ProductInfo/getProduct)는 다른 HTTP header로 보내진다.
  2. HTTP 요청은 network를 통해 server machine으로 전송된다.
  3. server는 message를 받으면, message header를 검사해서 어떤 service function을 호출해야하는지 확인하고 이를 service stub에 전달한다.
  4. service stub은 전달받은 message byte를 language-specific data structure로 parsing한다.
  5. parsed message를 이용하여 override한 buisness logic function을 호출한다. service function의 응답은 인코딩되어 클라이언트로 다시 전송된다.
  6. 응답 메시지는 client-side에서 위와 동일한 절차를 거쳐 unpacked and returned to the waiting client process

gRPC over HTTP/2

Response Message

image

gRPC Implementation Architecture

image
sangheee commented 2 years ago

gRPC: Beyond the Basics

Interceptor

remote function 실행 전/후로 실행시킬 common logic(such as logging, authentication, authorization, metrics, tracing, and so on)을 수행하기 위해 intercept incoming and outgoing RPC

Server-Side Interceptors

Error Handling

Load Balancing

Load-Balancer Proxy

you can use load-balancing solutions such as Nginx, Envoy proxy, etc., as the LB proxy for your gRPC applications.

Client-Side Load Balancing

There are two load-balancing policies supported in gRPC by default: _pickfirst and _roundrobin.

pickfirstConn, err := grpc.Dial(
  fmt.Sprintf("%s:///%s, exampleSheme, exampleServiceName).
  grpc.WithBalancerName("pick_first"),  // pick_first is the default option
  grpc.WithInsecure(),
)
if err != nil {
  log.Fatalf("did not connect: %v", err)
}
makeRPCs(pickfirstConn)

roundrobinConn, err := grpc.Dial(
  fmt.Sprintf("%s:///%s, exampleSheme, exampleServiceName).
  grpc.WithBalancerName("round_robin"),
  grpc.WithInsecure(),
)
if err != nil {
  log.Fatalf("did not connect: %v", err)
}
makeRPCs(roundrobinConn)
sangheee commented 2 years ago

Running gRPC in Production

Testing gRPC Application

Testing a gRPC Client

sangheee commented 2 years ago

The gRPC Ecosystem

gRPC Health Probe

If you are running your gRPC applications on Kubernetes, then you can run the grpc_health_probe to check to define Kubernetes’s liveness and readiness checks for your gRPC server pods.

sangheee commented 2 years ago
protoc --go_out=. --go-grpc_out=. ${SOME_PROTOBUF_FILE}

--go_out--go-grpc_out 왜 둘 다 줘야 하는가? 에 관해서 https://stackoverflow.com/a/60580149/9624199 에 설명이 나와있다.

요약하자면 --go_outprotoc-gen-go plugin, --go-grpc_outprotoc-gen-go-grpc plugin과 매칭된다. https://go.dev/blog/protobuf-apiv2 이런 이유로 protoc-gen-go는 no longer supports generating gRPC service definitions

For gRPC code, a new plugin called protoc-gen-go-grpc was developed by Go gRPC project. The plugins flag, which provided a way to invoke the gRPC code generator in the old-way, is deprecated.

protoc-gen-go-grpc

This tool generates Go language bindings of services in protobuf definition files for gRPC.

sangheee commented 2 years ago

https://developers.google.com/protocol-buffers/docs/proto#packages

In Go, the package directive is ignored, and the generated .pb.go file is in the package named after the corresponding go_proto_library rule.

sangheee commented 1 year ago

gRPC connections are sticky. gRPC uses HTTP/2, which multiplexes multiple calls on a single TCP connection. All gRPC calls over that connection go to one endpoint.

alexgituser commented 7 months ago

你好,你的邮件我已经收到  Alexwangyu