gRPC란?
gRPC(Google Remote Procedure Call)는 구글에서 개발된 고성능 RPC 프레임워크이다. HTTP/2에서 동작하며 양방향 스트리밍 및 흐름 제어를 제공한다.
gRPC는 원격으로 호출할 수 있는 메서드를 지정하여 서비스를 정의하는 개념이 기반이며 protobuf(IDL로 사용)를 기본 메시지 형식으로 사용한다.
IDL : Interface Definition Language
protobuf를 사용하여 더 효율적인 직렬화가 가능하고, Type을 명시적으로 체크할 수 있다.
gRPC의 특징
- 언어 독립성 : gRPC는 다양한 언어를 지원하여 서버와 클라이언트간 언어가 달라도 상호작용이 가능하다.
- 양방향 스트리밍 : HTTP/2를 기반으로 하여 클라이언트와 서버간에 양방향 스트리밍을 지원한다.
- 강력한 Type 체크 : 메시지의 형식을 프로토콜 버퍼로 정의 시 gRPC는 타입 체크를 제공한다.
- 높은 성능 : gRPC는 HTTP/2와 프로토콜 버퍼를 활용하여 높은 성능을 제공한다.
- Google API 연동 : Google API에는 인터페이스의 gRPC 버전이 제공되므로 애플리케이션에 Google 기능을 쉽게 빌드할 수 있다.
gRPC에서는 클라이언트 애플리케이션이 로컬 객체처럼 외부 서버 애플리케이션의 메서드를 직접 호출할 수 있기 때문에 분산 app과 서비스를 더 만들기 쉽다.
많은 RPC 시스템에서와 마찬가지로 gRPC는 서비스를 정의하고 매개변수와 반환 유형으로 원격으로 호출할 수 있는 메서드를 지정한다.
서버 측에서는 서버가 이 인터페이스를 구현하고 클라이언트 호출을 위해 gRPC서버를 실행한다.
클라이언트 측에서는 클라이언트가 서버와 동일한 메서드를 제공하는 stub을 가지고 있다.
예를 들어, 만약 서버에서 SayHello라는 메서드를 제공하면 클라이언트는 서버와 연결한 뒤 conn.GetUser 호출을 통해 서버가 제공하는 SayHello 메서드를 실행할 수 있다.
이에 대한 명세는 .proto
라는 파일을 생성하여 정의한 뒤 protobuf
로 빌드하면 생성할 수 있다.
protobuf
protobuf는 구글에서 개발한 언어와 플랫폼에 상관없이 데이터 직렬화를 가능하게 하는 데이터 구조다. 서로 다른 서비스끼리 데이터를 공유/저장하기 위해 사용된다.
protobuf는 XML, JSON과 같이 잘 알려진 데이터 형식보다 더 효율적인 방식으로 데이터를 관리하기 때문에 전송/저장 시 데이터를 더 적게 사용할 수 있다.
protocol buffer로 작업하기 위해서는 우선 데이터의 구조를 정의해야 한다.
확장자가 .proto
인 일반 텍스트 파일을 통해서 정의할 수 있으며 protocol buffer 데이터는 메시지로 구조화되고, 각 메시지는 필드라고 하는 일련의 name-value 쌍을 포함한다.
.proto
의 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
syntax = "proto3";
option go_package = "grpc/helloworld";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
위와 같이 .proto
파일을 생성한 뒤 버퍼 컴파일러인 protoc를 사용해서 사용하는 언어에 맞는 코드를 생성할 수 있다.
gRPC의 4가지 서비스 정의 방법
- 클라이언트가 서버에 단일 요청을 보내고 일반 함수 호출 마찬가지도 단일 응답을 받는 단항 RPC
1
rpc SayHello(HelloRequest) returns (HelloResponse);
- 클라이언트가 서버에 요청을 보내고 일련의 메시지를 읽을 수 있는 스트림을 다시 받을 수 있는 서버 스트리밍 RPC
1
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
- 클라이언트가 일련의 메시지를 작성하고 제공된 스트림을 사용하여 다시 서버로 보내는 클라이언트 스트리밍 RPC
1
rpc LotsOfReplies(stram HelloRequest) returns (HelloRequest);
- 클라이언트-서버 양방향 스트리밍 RPC
1
rpc LotsOfReplies(stream HelloRequest) returns (stream HelloResponse);
환경 구성(Mac M1 기준)
protoc 설치
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
- .proto 컴파일
1
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld/helloworld.proto
- 모듈화 컴파일하여 생성된 pb.go를 프로젝트에서 불러올 수 있도록 모듈화한다.
내 기준으론 gRPC 프로젝트에 helloworld라는 디렉토리를 담았으므로 .proto의 go package는 gRPC/helloworld 였다. 이 경우 gRPC 프로젝트에 모듈을 생성하면 불러올 수 있다.1 2
go mod init gRPC go mod tidy
- 결과
protobuffer를 읽어왔으므로 클라이언트에서 서버의 함수와 데이터를 통신으로 사용할 수 있다.
- 트러블 슈팅
1 2 3 4
protoc-gen-go: program not found or is not executable Please specify a program using absolute path or make sure the program is available in your PATH system variable --go_out: protoc-gen-go: Plugin failed with status code 1.
protoc를 못 읽어 오는 것이므로 PATH를 지정해준다.
1 2 3
vi ~/.zshrc export PATH=$PATH:$(go env GOPATH)/bin source ~./zshrc // 변경사항 적용
채팅
gRPC를 이용하여 서버와 클라이언트의 간단한 채팅을 만들어보았다.