Files
grpccanary/docs/GRPC.md
T

5.5 KiB

gRPC & Protocol Buffers 심화 학습

이 문서는 grpccanary 프로젝트의 3단계: gRPC 통신 구현에 대한 이론적 배경, 스키마 명세, 컴파일 기법 및 구체적인 소스코드 분석을 설명합니다.

gRPC는 HTTP/2를 기반으로 구축된 구글의 고성능 오픈소스 원격 프로시저 호출(RPC) 시스템입니다. 사물인터넷(IoT) 장비나 에이전트 간의 데이터 통신 시 가볍고 구조화된 데이터 통신을 유지하는 데에 가장 적합한 프레임워크입니다.


1. gRPC 개요 및 기술 배경

1.1 gRPC의 핵심 차별점

  • 강력한 스키마 계약: .proto 파일 하나로 서비스 통신 규약을 명확히 선언하고, 컴파일 단계에서 이를 바탕으로 여러 언어의 클라이언트/서버 코드를 자동 생성합니다. 따라서 런타임 단계에서의 통신 필드 누락이나 타입 불일치 버그를 완벽하게 방지합니다.
  • 이진 프로토콜 (바이너리 포맷): 텍스트가 아닌 컴팩트한 이진 형식을 사용하므로 데이터 크기가 매우 작고 네트워크 대역폭 리소스 효율이 뛰어납니다.
  • HTTP/2 기반: 하나의 네트워크 커넥션을 재사용해 다중화(Multiplexing) 전송이 가능하고, 실시간 스트리밍(양방향 스트리밍 포함) 서비스에 탁월한 환경을 제공합니다.

1.2 Protobuf (프로토콜 버퍼)의 장단점

  • 장점

    • 높은 전송 효율성: 데이터 교환 시 텍스트가 아닌 바이너리 인코딩 형식을 사용하므로 JSON에 비해 직렬화/역직렬화 속도가 매우 빠르고 크기도 가볍습니다.
    • 일관성 있는 코드 생성 (Stub): 동일한 정의서로부터 다국어 API 클라이언트를 빌드하여 중복 작성 오버헤드를 획득합니다.
    • 하위 호환성: 고유 필드 번호 매핑 방식을 사용하므로 스키마가 개정되어도 이전 시스템과의 통신 호환을 보장합니다.
  • 단점

    • 가독성 부재: 패킷이 암호화는 아니지만 바이너리로 전달되므로 사람이 브라우저 개발자 도구 등으로 바로 읽어 디버깅하기 곤란합니다.
    • 빌드 종속성: 명세 변경 시마다 Stub 코드를 컴파일하여 빌드에 바인딩하는 과정이 요구됩니다.

2. 인터페이스 명세서 (protoapi.proto)

저장소 루트의 protoapi.proto 파일은 의사 난수, 비밀번호, 날짜 데이터를 교환하는 Random 서비스를 제공하기 위해 아래와 같이 사양을 선언해 둡니다.

syntax = "proto3";

option go_package = "./protoapi/;protoapi";

service Random {
    rpc GetDate (RequestDateTime) returns (DateTime);
    rpc GetRandom (RandomParams) returns (RandomInt);
    rpc GetRandomPass (RequestPass) returns (RandomPass);
}

message RandomParams {
    int64 Seed = 1;
    int64 Place = 2;
}

message RandomInt {
    int64 Value = 1;
}

message DateTime {
    string Value = 1;
}

message RequestDateTime {
    string Value = 2;
}

message RequestPass {
    int64 Seed = 1;
    int64 Length = 8;
}

message RandomPass {
    string Password = 1;
}

3. Go Stub 컴파일 및 도구 체인

.proto 파일을 Go 파일로 출력하기 위해 프로토콜 버퍼 컴파일러(protoc)와 플러그인이 로컬에 갖추어져야 합니다.

3.1 OS별 설치 가이드

  • macOS:
    brew install protobuf
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
    
  • Linux:
    sudo apt install -y protobuf-compiler
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
    

3.2 컴파일 실행 명령어

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \
  --go-grpc_opt=paths=source_relative protoapi.proto

실행 결과로 protoapi/ 아래에 protoapi.pb.go(메시지 정의)와 protoapi_grpc.pb.go(인터페이스 및 원격 호출)가 자동 생성됩니다.


4. 실습 코드 구현 상세 분석

4.1 gRPC 서버 구현 (server.go)

  • 구조체 정의:
    type RandomServer struct {
    	protoapi.UnimplementedRandomServer
    }
    
    UnimplementedRandomServer를 임베딩하여, 향후 메서드가 새로 추가되더라도 기존 서버가 빌드 에러 없이 최소한의 호환( unimplemented 에러 응답 )을 가지게 강제합니다.
  • 서버 기동 흐름:
    server := grpc.NewServer()
    var randomServer RandomServer
    protoapi.RegisterRandomServer(server, randomServer)
    reflection.Register(server) // grpcurl 등 외부 디버깅 목적
    listen, _ := net.Listen("tcp", port)
    server.Serve(listen)
    

4.2 gRPC 클라이언트 구현 (client.go)

  • 연결 수립:
    conn, _ := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
    defer conn.Close()
    client := protoapi.NewRandomClient(conn)
    
    insecure.NewCredentials()를 전달하여 TLS를 건너뛴 채 평문으로 빠르고 간단한 로컬 테스트 환경을 구축합니다.
  • 원격 호출: client.GetDate(), client.GetRandom(), client.GetRandomPass()를 차례로 호출하여 매개변수와 결과를 콘솔로 확인합니다.