프로세스간 통신 방법인 RPC는 직접 구현하려고 하면 많은 노력과 전문 지식이 필요 합니다. 따라서 미리 구현된 형태인 gRPC를 활용해서 이용하는 형식이 많습니다. gRPC는 크게 네 가지 방법으로 통신을 구현합니다.
하나의 요청과 하나의 응답으로 처리하는 방식
클라이언트는 하나의 요쳥을 보내지만 서버는 스트림으로 응답을 보내는 방식
클라이언트는 스트림으로 요청을 보내고 서버는 하나의 응답으로 처리하는 방식
클라이언트와 서버 모두 스트림으로 처리
스트리밍과 그렇지 않은 것의 차이는 proto의 stream 키워드로 구분할 수 있습니다. 따라서 아래의 해당 예시 처럼 쉽게 처리할 수 있습니다.
stream 키워드는 요청과 응답에 사용해서 해당 방식을 설명할 수 있습니다. 물론 stream 키워드를 통해 결과를 보면 사용한 것과 아닌것의 결과가 다르다는 것을 확인할 수 있습니다. 일반적으로 아래와 같이 작성합니다.
syntax = "proto3";
service UserService {
// Unary
rpc GetUserUnary (UserRequest) returns (UserResponse);
// Server streaming
rpc GetUserServerStream (UserRequest) returns (stream UserResponse);
// Client streaming
rpc GetUserClientStream (stream UserRequest) returns (UserResponse);
// Bi-directional streaming
rpc GetUserStream (stream UserRequest) returns (stream UserResponse);
}
실제로 해당 proto를 통해 만들어진 코드를 보면서 어떻게 다른지 한번 살펴보겠습니다. 먼저 kotlin 코드를 보면서 어떤 면이 다른지 한번 비교해 보겠습니다.
// response를 stream으로 생성한 결과
fun getUsersStream(request: User.GetUsersRequest, headers: Metadata = Metadata()):
Flow = serverStreamingRpc(
channel,
UserServiceGrpc.getGetUsersStreamMethod(),
request,
callOptions,
headers
)
// 요청 응답 모드 단일 요청으로 생성한 결과
suspend fun getUsers(request: User.GetUsersRequest, headers: Metadata = Metadata()):
User.GetUsersResponse = unaryRpc(
channel,
UserServiceGrpc.getGetUsersMethod(),
request,
callOptions,
headers
)
실제로 코드를 분석하면 response를 Flow
go로 생성된 코드도 stream 처리와 unary 처리가 확실히 코드가 다름을 확인했습니다.
작성중....
// 요청 응답 모드 단일 요청으로 생성한 결과
func (c *loginServiceClient) LoginSimpleRPC(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) {
out := new(LoginResponse)
err := c.cc.Invoke(ctx, "/rpc_auth.LoginService/LoginSimpleRPC", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// response를 stream으로 생성한 결과
func (c *loginServiceClient) LoginServerStreamRPC(ctx context.Context, in *LoginRequestList, opts ...grpc.CallOption) (LoginService_LoginServerStreamRPCClient, error) {
stream, err := c.cc.NewStream(ctx, &LoginService_ServiceDesc.Streams[0], "/rpc_auth.LoginService/LoginServerStreamRPC", opts...)
if err != nil {
return nil, err
}
x := &loginServiceLoginServerStreamRPCClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
stream 코드 작성 재정의