-
RPC, gRPC, stub📖 개발 공부 2023. 8. 3. 22:23
RPC
RPC는 Remote Procedure Call의 약자로 분산 네트워크 환경에서 조금 더 직관적인 프로그래밍을 가능하게 해주기 위해 등장하였다.
Server-Client Model에서 상세한 정보를 감추고 개발자는 각 로직에 집중할 수 있게, Client와 Server는 메소드를 호출하는 것처럼 개발하면 된다.
caller/callee
- 개발자가 필요한 비즈니스 로직을 생성하고 정의된 IDL(interface definition language)로 작성하여 stub 을 호출한다.
Stub
- RPC에서 클라이언트와 서버 간에 통신을 하기 위해 Stub이 사용된다.
- Stub compiler 가 IDL 파일을 읽어 원하는 language 로 생성하고 파라미터를 변환(Marshalling)/역변환(Marshalling) 처리하여 RPC 프로토콜로 전달한다.
- Stub은 네트워크 통신을 추상화하여 개발자가 편리하게 RPC를 사용할 수 있도록 한다. stub이 있으면 개발자들은 백엔드 서버가 완전히 구현되지 않은 상태에서도 클라이언트를 독립적으로 개발하고 테스트할 수 있다.
RPC runtime
- 통신하여 각 메세지를 전달하게 된다.
gRPC
gRPC는 Google에서 개발한 고성능 원격 프로시저 호출(RPC) 프레임워크로서, Protocol Buffers를 사용하여 강력하고 효율적인 통신을 지원한다.
gRPC Stub은 gRPC 서비스와 클라이언트 간의 통신을 쉽게 처리하기 위해 사용되는 클라이언트 측 프록시다.
gRPC 특징
높은 생산성과 효율적인 유지보수
- IDL(Identity Definition Language)로 protocol buffers(protobuf)사용한다. IDL만 정의하면 높은 성능을 보장하는 서비스와 메세지에 대한 소스코드가 각 언어에 맞게 자동 생성된다.
- 따라서 개발자들은 생성된 코드를 클라이언트, 서버 간의 사용 언어에 구애받지 않고 사용하기만 하면 되며 정해진 규약을 공통으로 사용하기 때문에 의사소통 비용이 감소하게 된다.
다양한 언어와 플랫폼 지원
높은 메시지 압축률과 성능
- 문자열을 사용하는 JSON과 xml과는 다르게, protobuf는 binary 데이터를 주고 받는다.
- gRPC 는 내부적으로 HTTP/2 사용하여 헤더 압축률이 높고 protobuf 에 의해 통신시점에는 바이너리 데이터로 통신하기 때문에 메시지 크기가 작다.
protobuf란?
IDL(Identity Definition Language)로 protocol buffers(protobuf)를 사용한다. IDL만 정의하면 높은 성능을 보장하는 서비스와 메세지에 대한 소스코드가 각 언어에 맞게 자동 생성된다.
따라서 개발자들은 생성된 코드를 클라이언트, 서버 간의 사용 언어에 구애받지 않고 사용하기만 하면 되며 정해진 규약을 공통으로 사용하기 때문에 의사소통 비용이 감소하게 된다.
이렇게 작성된 proto 파일을 통해서 protoc 컴파일러를 통해 각 언어로 소스 코드가 생성된다. (밑에 예시에서 자세히 알 수 있다.)
gRPC 활용 예시
proto 파일로 서비스 정의
// proto 파일로 서비스 정의 service OrderService { rpc CreateOrder(OrderRequest) returns (OrderResponse); } // 주문을 생성하기 위한 서비스 정의 service OrderService { rpc CreateOrder(OrderRequest) returns (OrderResponse); } // 주문 정보를 담고 있는 데이터 형식 정의 message OrderRequest { int32 productId = 1; int32 quantity = 2; } message OrderResponse { string status = 1; }
인터페이스(자동 생성)와 인터페이스 구현
// gRPC Stub 인터페이스 (gRPC에서 자동 생성되는 코드) interface OrderServiceStub { fun createOrder(request: OrderRequest): OrderResponse } // gRPC Stub 구현하기 class OrderServiceStubImpl(private val channel: ManagedChannel) : OrderServiceStub { private val blockingStub: OrderServiceBlockingStub = OrderServiceGrpc.newBlockingStub(channel) override fun createOrder(request: OrderRequest): OrderResponse { return blockingStub.createOrder(request) } }
클라이언트에서의 사용법
import io.grpc.ManagedChannelBuilder fun main() { // gRPC 서버와 연결을 설정 val channel = ManagedChannelBuilder.forAddress("localhost", 50051) .usePlaintext() .build() // gRPC Stub 생성 // 비동기적으로 처리하려면 OrderServiceCoroutineStub로 stub을 만들 수 있다. val orderServiceStub = OrderServiceGrpc.newBlockingStub(channel) // 주문 생성 요청 val request = OrderRequest.newBuilder() .setProductId(123) .setQuantity(2) .build() // 주문 생성 메서드 호출 및 결과 반환 val response = orderServiceStub.createOrder(request) println("주문 생성 결과: ${response.status}") }
gRPC의 (잘 정의된) 상태코드
Code Number Description OK 0 성공적으로 처리했을 때 반환한다. CANCELLED 1 요청자가 요청을 취소했을 때 반환한다. UNKNOWN 2 알 수 없는 에러, 서버 문제일 때 반환한다. INVALID_ARGUMENT 3 클라이언트가 잘못된 인수를 지정했을 때 반환한다. DEADLINE_EXCEED 4 작업을 완료하기 전에 데드라인을 넘겨버렸을때 반환한다. 상태를 변경하는 시스템의 경우 이 에러가 발생을 해도 실제로 상태를 변경해버렸을 수 있다.
(예를 들어 성공적인 작업에 대한 응답이 늦게 반환된 경우)NOT_FOUND 5 요청한 엔티티를 찾을수 없을때 반환한다. ALREADY_EXISTS 6 생성하려는 엔티티가 이미 존재하면 반환한다. PERMISSION_DENIED 7 함수의 호출자가 작업을 처리하기 위한 권한이 없으면 반환한다. 728x90반응형'📖 개발 공부' 카테고리의 다른 글
Cache / Caching 전략 / Cache Expiration, Eviction (0) 2023.08.14 [HTTP] HTTP 메서드 (0) 2023.08.09 재고시스템으로 알아보는 동시성이슈 해결방법 (0) 2023.08.02 CQRS 패턴 (0) 2023.07.25 [Kubernetes] sidecar pattern (사이드카 패턴) (0) 2023.07.10