Adventure42

the answer to the ultimate question of life, the universe, and everything

gRPC(Remote Procedure Call)

04 Oct 2022 » ProcessCommunication


Intro to gRPC

gRPC란?

RPC(Remote Procedure Call) that uses protocol buffers as its IDL (Interface Definition Language) and its underlying message interchange format. gRPC를 통해 client는 같은 또는 다른 system에 있는 server의 method를 마치 local object와 같이 쉽게 호출할 수 있다. 다른 다양한 RPC system들과 같이 gRPC는 remote하게 호출되어 수행될 수 있는 methods(their parameters and return types)를 설정하여 server가 제공 할 수 있는 service를 define할 수 있게 해준다.

gRPC가 구현되면, server와 client는 다음과 같은 역할을 수행 한다.

SERVER : The server implements an interface and runs a gRPC server to handle client calls.

CLIENT : The client has a stub (stub = server와는 다를 수 있는 language로 구현된 client를 의미함) that provides the same methods as the server.

gRPC

grpc.io 사이트grpc git repository에서 제공되는 examples를 가지고 Quick startBasic tutorial을 따라하면 대략적으로 어떻게 service를 위한 interface가 구현되는 지 알 수 있다.


gRPC는 Protocol Buffers를 활용한다.

(Protocol buffer란? Google에서 structured data의 serialization을 수행하기위해 만든 open source mechanism이다.)

  1. 먼저 proto file로 serialize할 data의 structure를 define해야 함. protocol buffer data는 “message”로 구성되어 있음. 각 “message” is a small logical record of information containing a series of name-value pairs called “fields”. 일반적으로 syntax는 proto3 (protocol buffers version 3)를 사용한다.

    proto 은 단순 .proto extension을 가진 txt 파일이다. 여기에서 gRPC를 통해 제공하려는 service들을 define한다. RPC methods parameter들과 return types are specified as protocol buffer messages.

  2. Data structure이 define되었으면, protocol buffer compiler protoc을 사용해서 data access class를 생성한다. 사용하려는 programming language로 data access class를 생성할 수 있다.

    protoc은 special gRPC plugin을 통해서 proto file의 내용을 기반으로 code를 생성해낸다. 다음 code들이 생성된다: gRPC client and server code, regular protocol buffer code for populating, serializing, and retrieving message types

  3. 생성된 data access class를 활용하여 application의 기능을 제공할 수 있도록 customized된 client와 server code를 작성한다.


Example

examples에 예시로 제공된 route_guide package를 보면,

route_guide.proto를 작성한 후, protoc을 통해 compile하면, route_guide_pb2.pyroute_guide_pb2_grpc.py가 생성된다.

그 후, 구현하려는 service 기능을 직접 route_guide_server.pyroute_guide_client.py에서 설정할 수 있다.

route_guide_server.py에서는 compiling을 통해 생성된 route_guide_pb2_grpc.RouteGuideServicer class의 subclass인 RouteGuideServicer class를 define하고 이 class의 methods로 proto file에서 define했던 service 기능들을 상세하게 구현할 수 있다.

그 후, server쪽은 다음과 같이 실행할 수 있다.

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
        RouteGuideServicer(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    logging.basicConfig()
    serve()

route_guide_client.py에서는 client가 호출하고자 하는 (proto file에서 define했던) 기능들을 define할 수 있다. compiling을 통해 생성된 route_guide_pb2_grpc.RouteGuideStub class의 객체 (“stub”)를 생성하여 여기에서 define한 method를 호출한다. 대략적인 code는 다음과 같다.

def run():
    # proto file에 GetFeature, ListFeatures, RecordRoute, RouteChat 이렇게 4 가지 service가 define된 case에 해당한다.
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = route_guide_pb2_grpc.RouteGuideStub(channel)
        print("-------------- GetFeature --------------")
        guide_get_feature(stub)
        print("-------------- ListFeatures --------------")
        guide_list_features(stub)
        print("-------------- RecordRoute --------------")
        guide_record_route(stub)
        print("-------------- RouteChat --------------")
        guide_route_chat(stub)


if __name__ == '__main__':
    logging.basicConfig()
    run()



RPC Definition

하나의 system 내에서 또는 network으로 연결된 두개의 system사이에서 conventional local procedure calling이 확장되어서 distributed, client-server based application이 구현된 것이다.


IDL Definition

Interface에 대한 정의를 진행하는 언어. 각각의 시스템을 연결하는 역할을 수행한다. RPC로 연결되는 시스템들이 같은 형태의 언어를 사용할 수도, 다른 형태의 언어를 사용할 수도 있다. 다른 언어간의 procedure가 서로의 요청에 대해서 이해하기 위해서는 interface를 통해 규칙을 세워두고 각자의 시스템이 이해할 수 있는 형태로 변형해야한다.


RPC 동작방식

Caller(client process)와 Callee(server process) 사이에서 message가 오고감.

  1. Caller(client) calls a procedure.
  2. Caller가 Callee(server)에게 request message를 보냄. Request message contains remote procedure’s parameters.
  3. Callee는 request를 기다리고 있다가, receives the request and starts procedure execution.
  4. Callee executes the procedure.
  5. Callee sends reply to the Caller. Reply message contains result of the procedure execution.
  6. Caller은 reply를 기다리고 있다가, resumes execution.
  7. Callee continues to wait for the next request.


RPC mechanism:

RPC_mechanism

  1. 클라이언트가 일반적인 방식으로 파라미터를 넘겨 client stub procedure를 호출한다. client stub은 클라이언트를 소유한 주소의 공간 내에 거주한다.
  2. client stub이 파라미터들을 메세지로 모은다. 여기서 모은다는 것에 파라미터의 표현을 표준 포맷으로 변경하고 각 파라미터를 복사해서 메세지로 넣는 것도 포함된다.
  3. client stub은 원격 서버 머신으로 메세지를 보내는 계층인 transport layer로 메세지를 보낸다.
  4. 서버에서, transport layer는 메세지를 server stub으로 보낸다. server stub은 또 파라미터들을 모아주고 일반적인 프로시저 호출 메커니즘을 사용하여 요구된 서버 루틴을 호출한다.
  5. 서버 프로시저가 완료될 때, 서버 프로시저는 server stub으로 반환된다. (이를테면 일반적인 프로시저 호출 반환값을 통해), server stub은 결과 값들을 모아서 메세지에 넣고, transport layer에 메세지를 보낸다.
  6. transport layer는 결과 메세지를 다시 client transport layer로 보내고 client transport layer는 그 결과를 또 client stub에게 전달한다.
  7. client stub은 반환 파라미터들과 실행 결과값을 다시 해체한다.



References

  1. “Introduction to gRPC” https://grpc.io/docs/what-is-grpc/introduction/
  2. https://velog.io/@jakeseo_me/RPC%EB%9E%80

Related Posts