티스토리 뷰

gRPC

[gRPC] Nested Type, Update, Unknown FIeld

Jaime.Lee 2021. 8. 6. 10:30

중첩 타입(Nested Type)

다른 메시지 타입 안에 메시지 타입을 정의하여 사용할 수 있습니다.

아래 예제는 SearchResponse 안에 Result 라는 타입을 정의해서 사용한 것 입니다.

이전 포스팅에서 enum을 안에 정의한 것과 동일하게 사용할 수 있습니다.

사실 이 글을 보시는 분들은 소스 코드가 더 익숙하실 거라 자세한 설명보다는 예제로 접하는 게 더 익숙하실 거 같습니다.

message SearchResponse {
  message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3;
  }
  repeated Result results = 1;
}

만약에 위 처럼 선언한 메시지 타입을 다른 메시지 타입에서 사용해야 할 경우 ParentType.Type 으로 참조할 수 있습니다.


message SomeOtherMessage {
  SearchResponse.Result result = 1;
}

아래 예시처럼 원하는 만큼 더 깊이 중첩시킬 수도 있습니다.

message Outer {                  // Level 0
  message MiddleAA {  // Level 1
    message Inner {   // Level 2
      int64 ival = 1;
      bool  booly = 2;
    }
  }
  message MiddleBB {  // Level 1
    message Inner {   // Level 2
      int32 ival = 1;
      bool  booly = 2;
    }
  }
}

메시지 타입 업데이트 (Updating A Message Type)

기존 메시지 타입이 더 이상 모든 요구사항을 충족하지 못하는 경우(추가 필드가 필요하다든지)에도 기존 메시지 포맷을 유지하고 싶은 상황이 있습니다.

이럴 때 기존 코드를 유지하면서 메시지 타입을 업데이트 할 수 있습니다.

아래 룰들만 기억하시면 됩니다.

(1) 기존 필드의 필드 번호를 변경하지 마세요.

(2) 새 필드를 추가하면 이전 메시지 형식을 사용하여 코드로 직렬화된 모든 메시지를 새로 생성된 코드로 파싱할 수 있습니다. 새 코드가 이전 코드에서 생성된 메시지와 제대로 상호 작용할 수 있도록 이러한 요소의 기본 값을 염두에 두어야 합니다. 마찬가지로, 새 코드로 생성된 메시지는 이전 코드로 파싱할 수 있습니다. 이전 바이너리는 파싱할 때 새 필드를 무시하기만 하면 됩니다. 자세한 내용은 아래 정리할 "알 수 없는 필드(Unknown Field)"룰 참조하세요.

(3) 업데이트 된 메시지 타입에서 필드 번호가 다시 사용되지 않는다면 해당 필드는 제거할 수 있습니다. 대신 필드 이름을 바꾸거나 접두사 OBSOLETE_를 추가하거나 필드 번호를 예약하여 .proto의 향후 사용자가 실수로 번호를 재사용할 수 없도록 하는 것을 권장합니다.

(4) int32, uint32, int64, uint64, bool은 모두 호환됩니다. 이는 앞으로 이전 버전, 이후 버전에 대해 호환성을 유지한채로 필드를 바꿀 수 있음을 의미합니다. 만약에 해당 타입에 맞지 않는 숫자 등을 넣었을 경우 C++에서는 숫자를 캐스팅한 것과 동일한 결과를 얻을 수 있습니다. (64bit 숫자를 32bit 숫자로 읽을 경우 32bit에서 truncated)

(5) sint32sint64는 서로 호환되지만 다른 정수 유형과 호환되지 않습니다.

(6) stringbytesbytes가 valid한 UTF-8일 경우 호환됩니다.

(7) 바이트에 인코딩된 버전의 메시지가 포함된 경우 포함된 메시지는 바이트와 호환됩니다.

(8) fixed32sfixed32와 호환되고 fixed64sfixed64와 호환됩니다.

(9) string, bytes, message fields의 경우 optionalrepeat와 호환됩니다. 직렬화된 데이터가 주어졌을 때 이를 역직렬화해서 사용하는 클라이언트는 repeated 필드는 선택사항(0~N개)으로 간주하고, 기본 타입 필드인 경우 마지막 입력 값을 사용하고, 메시지 타입 필드인 경우 모든 입력 요소를 병합합니다. 일반적으로 boolenum을 포함한 숫자 타입은 안전이 보장되지 않습니다. 숫자 타입의 repeated 필드는 압축 형식으로 직렬화 될 수 있으며, 이는 optional로 인식하는 경우 제대로 파싱할 수 없습니다.

(10) enumint32, uint32, int64uint64와 호환됩니다만 값이 맞지 않을 경우 truncated 됩니다. 그러나 클라이언트에서 역직렬화 될 때는 이를 다르게 취급할 수 있습니다. 예를 들어 인식되지 않는 proto3 열거형 타입은 메시지에 보존되지만 메시지가 역직렬화될 때 이것이 표현되는 방식은 언어에 따라 다릅니다. int 필드는 항상 값을 유지합니다.

(11) 단일 값을 새로운 oneof의 멤버로 변경하는 것은 안전하고 이진 호환 가능합니다. 한 번에 둘 이상의 코드 세트가 없는 경우 여러 필드를 새 필드로 이동하는 것이 안전할 수 있습니다. 필드를 기존 필드로 이동하는 것은 안전하지 않습니다.

Unknown Fields

Unknown Field는 파서가 인식하지 못하는 필드를 나타내는 데이터입니다.

예를 들어, 이전 바이너리가 새 바이너리에서 보낸 데이터를 새 필드로 파싱할 때 새 필드는 이전 바이너리에서 알 수 없는 필드가 됩니다.

원래 proto3 메시지는 구문 분석 중에 항상 Unknown Field를 무시했지만 3.5 버전에서는 proto2 동작과 일치하도록 Unknown Field를 다시 보존하게 하였습니다.

버전 3.5 이상에서 Unknown Field는 파싱 중에 유지되고 직렬화된 결과물에 포함됩니다.


본 포스팅은 gRPC 공식 문서를 참고하여 작성하였습니다.

댓글