지금 회사의 아키텍쳐는 마이크로서비스 아키텍쳐 구조로 되어 있다. 지금 구조에서 Client 와 Server 간 통신에는 큰 문제 없었으나, 마이크로서비스 간의 통신을 할 때가 문제였다. Rest Api 방식으로 통신이 가능 했으나 마이크로서비스간의 인증 문제와 서버간의 통신을 좀 더 빠르고 안전하게 다룰 수 있는 방법을 찾아보기로 하였다. 그 중 찾은 방법은 gRPC 프레임워크를 사용한 서비스간의 통신 방법을 찾았다.
현재 gRPC에서 특징인 HTTP/2, 프로토콜버퍼는 현재 브라우저에서 많은 지원을 하지 않기 때문에 클라이언트 단은 Rest API로, 마이크로서비스 간 통신은 gRPC로 하기로 하였다. gRPC를 이용하기 전에 RPC가 정확히 어떤 것인지 이해가 필요해 조사를 조금 해보았다.
RPC는 Remote Procedure Call의 약자로 네트워크로 연결된 서버 상의 프로시저(함수, 메서드등)을 원격으로 호출할 수 있는 프로세스 간 통신 기술이다. RPC를 이용하면 프로그래머는 원격지의 자원을 내 것처럼 사용 할 수 있다. IDL(Interface Definition Language) 기반으로 다양한 언어를 가진 환경에서도 쉽게 확장이 가능하며, 인터페이스 협업에도 용이하다는 장점이 있다.
* IDL 이란 한 언어에 국한되지 않는 언어중립적인 방법으로 인터페이스를 표현함으로써, 같은 언어를 사용하지 않는 소프트웨어 컴포넌트 사이의 통신을 가능하게 한다.
※지원 언어: C++, Java, Python, Ruby, Node.js, C#, Go, PHP, Objective-C ...
RPC의 핵심 개념이다. 서버와 클라이언트는 서로 다른 주소 공간을 사용하므로, 함수 호출에 사용된 매개 변수를 변환해야 된다. 이때 Stub을 사용하여 매개 변수를 변환 한다.
Client stub : 함수 호출에 사용된 파라미터의 변환(Marshalling, 마샬링) 및 함수 실행 후 서버에 전달 된 결과 변환을 담당한다.
Server stub : 클라이언트 요청시 전달한 매개 변수의 역변환(Unmarshalling, 언마샬링) 및 함수 실행 결과 변환을 담당한다.
① IDL(Interface Definition Language)을 사용하여 호출에 대한 인터페이스를 정의한다.
② Stub Code에 명시된 함수는 원시코드의 형태로, 상세 기능은 server에서 구현된다.
③ Client stub은 RPC 런타임을 통해 함수를 호출 한다.
④ Server는 수신된 procedure 호출에 대한 처리 후 결과 값을 반환한다.
⑤ 최종적으로 Client는 Server의 결과 값을 반환받고, 함수를 Local에 있는 것 처럼 사용할 수 있다.
gRPC
는 Google이 개발한 고성능 오픈소스 범용 RPC 프레임워크이다. gRPC에서 클라이언트 애플리케이션은 다른 머신의 서버 애플리케이션에 있는 메소드를 로컬 객체처럼 직접 호출할 수 있으므로 분산 애플리케이션 및 서비스를 더 쉽게 만들 수 있다.
gRPC는 HTTP/2를 사용하고 프로토콜 버퍼로 데이터를 전달한다. 그렇기에 Proto fILE만 배포하면 환경과 프로그램 언어에 구애받지 않고 서로간의 데이터 통신이 가능하다.
HTTP/1은 클라이언트의 요청이 올때마다 connection을 생성해야 하지만 HTTP/2는 한 conection으로 통신이 가능하며 서버와 클라이언트가 서로 동시에 데이터를 주고 받을 수 있다.
높은 Header 압축률을 보장하고 중복을 제거 하기에 HTTP/1에 비해 훨씬 효율적이다.
클라이언트 요청 없이도 서버가 리소스를 전달 할 수 도있기 때문에 클라이언트 요청을 최소화 할 수 있다.
* 직렬화란 데이터 표현을 바이트 단위로 변환하는 작업을 말한다
syntex = "proto3";
message Request {
string feild1 = 1;
int32 field2 = 2;
int32 filed3 = 3;
}
▶ Field Tag (= Field Number)
- 메시지에 정의돈 필드들은 각각 고유한 번호를 가지게 되고 이는 Encoding 이후 binary data에서 필드를 식별하는 데 사용된다.
- Field Tag는 최소 1, 최대 536,870,911(=229-1)로 지정 가능하며, 19000~19999 는 프로토콜 버퍼 구현을 위해 제한된 값이므로 사용할 수 없다.
▶ syntax
- syntax
는 어떤 버전의 문법을 따를지 선언할 수 있다. 명시하지 않을 시 default로 proto version 2 문법을 따른다.
- Proto 2는 C++, Java, Python, Go
를 지원.
- Proto 3은 C++, Java, Python, Go, Ruby, Objective-C, C#, JavaScript, PHP, Dart
를 지원
▶ Proto File Field Rule
- required : 필수로 가져야 할 필드 (only use proto2)
- optional : 해당 필드를 가지지 않거나 하나만 가짐 (only use proto2)
- repeated : 임의 반복 가능한 필드 (번호 및 값의 순서는 보존)
* [packed=true] 옵션 : key-value 쌍 형태에서 value만 반복
option java_package";
를 지정하지 않으면 자바패키지로 사용한다.// Unary RPC
service Greeter {
rpc SayHello ( HelloRequest ) returns ( HelloReply ) {}
}
//양방향 Streaming RPC
service FileService {
rpc FileUpload ( stream FileUploadRequest ) returns ( FileUploadReply ) {}
}
참고 문서.