본문 바로가기
프로그래밍/gRPC

gRPC 동작 원리

by 나도한강뷰 2022. 8. 22.

실질적으로 gRPC의 경우, proto에서 정의내려준 message의 종류와, service의 종류에 맞춰서 client와 server에서 들어온 데이터를 처리하는 것에만 신경쓰면 되기때문에, gRPC가 어떻게 구현되고, 인코딩되며, 네트워크에서 작동하는 세부방식에 대해서는 몰라도 무관하다.

 

하지만, 알고있는게 나쁜것은 아니고, 어디가서 아는척도 할 수 있다?

 

첫번째로 gRPC의 흐름에대해서 살펴보자.

1. client는 프로시저를 호출한다. service("input message")

2. client stub은 그에 맞춰서 HTTP POST 요청을 인코딩 메세지로 생성한다.

3. HTTP/2프로토콜을 이용해서 server에 전달된다.

4. server는 메세지 헤더를 통해서 알맞는 server stub으로 메세지를 전달한다.

5. server stub은 인코딩 메세지를 디코딩하며 데이터 구조를 알맞게 파싱한다.

6. 그에 맞는 service("input message")를 호출한다

출처: https://meetup.toast.com/posts/261

이러한 과정은 일반적은 RPC와 동일한 흐름을 갖고있으며, gRPC의 경우 인코딩 디코딩을 위해서 프로토콜 버퍼를 사용한다는것이 차별점이다.

 

※프롵토콜 버퍼란, 구글에서 개발하여서 오픈소스로 제공하고있는 직렬화 데이터 구조이다. 자세한 설명은 아래 티스토리를 참조하면 될것같다. https://jeong-pro.tistory.com/190

 

결국 미리정해놓은 proto의 구조를 기반으로해서 내가 보내는 메세지(구조체)를 UTF-8등의 형태로 인코딩해서 보내주는 것이라고 생각하면 되겠다.


그렇다면 프로토콜 버퍼는 어떤 규칙을 가지고 메세지를 인코딩 하는지 살펴보겠다.

syntax = "proto3"

service ServiceInfo {
	rpc getService(ServiceID) return (Service);
}

message Service {
	string id = 1;
    string ip = 2;
    string description =3;
}

message ServiceID {
	string value = 1;
}


service, err := c.GetService(, &pb.ServiceID{Value: "15"})

프로토콜 버퍼는 메세지가  |필드 인덱스| 와이어 타입 | 값 |의 형태를 갖도록 인코딩된다.

field index + wire type은 tag라고 불린다. 메세지의 어떤 놈인지 구분할 수 있는 tag와 같은 역할을 하기때문이다. 

 

와이어 타입의 경우 아래와 같이 데이터 형식을 의미한다.

참조: https://medium.com/naver-cloud-platform/nbp-%EA%B8%B0%EC%88%A0-%EA%B2%BD%ED%97%98-%EC%8B%9C%EB%8C%80%EC%9D%98-%ED%9D%90%EB%A6%84-grpc-%EA%B9%8A%EA%B2%8C-%ED%8C%8C%EA%B3%A0%EB%93%A4%EA%B8%B0-2-b01d390a7190

위와같이 작성할시 message는 필드 인덱스 1이며, 와이어 타입은 2, 필드 값은 15을 갖도록 인코딩 하게된다.

와이어 타입은 3bit이며 이것을 고려하면, 필드 인덱스 00000001, 와이어 타입 00000010은 0000 1010으로 합쳐지게 된다. 그리고 필드 값 "15"는 UTF-8인코딩 값이 \x31 \x35이다.

이때 필드 값에 따라서 인코딩 값의 길이가 결정되기 때문에, 인모딩된 값의 길이를 표시하는 부분이 앞에 붙게된다.

최종적으로 인코딩 값의 길이를 나타내는 A 02와 31 35가 합쳐져서 필드 값은 A 02 31 35가 된다.

 

기본적인 인코딩 방식은 위와 같으며,  필드 값의 인코딩 방식은, 와이어 타입에 따라서 다르다. Varint, nonvarint, length-delimited에 따라 각각 다른 식으로 인코딩을 하게된다.

인코딩 방식은 위의 와이어 타입 참조 링크를 타고 들어가면 확인할 수 있다.

 


이렇게 생성된 인코딩 메세지는 HTTP/2를 통해서 client에서 server로 빠르게 전달되게 된다.

HTTP/2에서는 프레임/ 메세지/ 스트림이라는 단위를 이용해서 통신을 하게된다.

  • 프레임: 가장 작은 통신단위, 프레임에는 각각의 헤더가 있으며, 헤더를 통해서 어느 스트림에 포함되어있는지를 파악한다.
  • 메세지: 하나이상의 프레임으로 구성된 온전한 프레임 시퀀스
  • 스트림: 설정된 연결에서의 양방향 바이트 흐름이며, 스트림은 하나이상의 메세지를 전달한다.

메세지는 request message와 response message로 나뉘며,

request message는 통신을 시작하는 메세지이다.

request message = | header | length-prefix framing message | EOS | 의 형태로 이루어져 있다.

 header는 아래와 같이 구성되어있다.

:method = POST // gRPC는 무조건 POST이다
:scheme = http // ssl적용시 https로 변경
:path = /ServiceInfo/getService // 경로를 지정, service name/ method name형태
:authority = url.com //uri의 host name
te = trailers //미호환의 proxy탐지를 정의, gPRC는 trailers여야한다
grpc-timeout = 1S // time out, default = infinity
content-type = application/grpc // grpc는 옆에와 같이 시작해야한다. 아닐경우 415 error발생
grpc-encoding = gzip //메세지 압축 유형
authorization = Bearer xxx // 보안 토큰

lenght-prefix framing message는 위에서 설명한 인코딩 데이터가 들어가게 된다.

 

response message는 request에대한 응답 메세지이다.

response message = | header | ...nil or lenght-prefix framing message ... | trailer | 의 형태로 이루어져 있다.

header는 아래와 같이 구성되어있다.

:status = 200 // http request code
grpc-encoding = gzip
content-type = application/grpc

'프로그래밍 > gRPC' 카테고리의 다른 글

gRPC의 통신 패턴  (0) 2022.08.20
gRPC 소개  (0) 2022.08.14