message 들은 일련의 Key-Value 쌍으로 이루어진 binary data로 인코딩된다.
Key는 Field Number 뿐만 아니라, 해당 Field의 data type을 지시하는 "Wire Type"을 표현.
Key 구성
Wire Type
Ex) string query = 1
Key = (field_number << 3) | wire_type
Key = 00001000 | 00000010 = 00001010 = 0x0A
Ex) int32 result_per_page = 3
Key = 00011_000
Key = 0x18
정수를 Serializing 하는 Varints Encoding.
Varints에 포함되는 정수형 타입들은 첫 byte의 1bit를 무조건 뒷 byte에 대한 지시 역할을 하는 msb(most significant bit)를 가지고 있음.
Field number는 정수형이므로 Varints Encoding 법칙을 따른다.
Ex) 300 Encoding
300을 이진수로 표현(2byte 필요)
==> 256 + 32 + 8 + 4 = 1|00101100
Varints 직렬화를 위해선 byte 당 msb가 포함돼야 하므로 7bit 단위로 구분.
==> 10|0101100
==> X0000010_X0101100
least significant group first 룰에 맞게 byte를 역순으로 나열.
==> X0101100_X0000010
msb 설정
==> '1'0101100_'0'0000010
1 : 뒤에 데이터 있음.
0 : 뒤에 데이터 없음.
디코딩은 거꾸로 수행한다.
Signed Integers
만약 protocol buffer에서 음의 정수를 표기한다면 signed int(sint) 형을 사용하는게 효율적.
일반 int형에서는 음수로 사용 시 절댓값에 관계없이 항상 고정된 byte 크기를 잡는데, signed int형은 ZigZag Encoding으로 이미 부호있는 정수를 부호없는 정수로 매핑시켜 두었기 때문. ??
use uint32 if the value cannot be negative
use sint32 if the value is pretty much as likely to be negative as not (for some fuzzy definition of "as likely to be")
use int32 if the value could be negative, but that's much less likely than the value being positive (for example, if the application sometimes uses -1 to indicate an error or 'unknown' value and this is a relatively uncommon situation).
If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes long - it is, effectively, treated like a very large unsigned integer. If you use one of the signed types, the resulting varint uses ZigZag encoding, which is much more efficient.
ZigZag encoding maps signed integers to unsigned integers so that numbers with a small absolute value (for instance, -1) have a small varint encoded value too.
It does this in a way that "zig-zags" back and forth through the positive and negative integers, so that -1 is encoded as 1, 1 is encoded as 2, -2 is encoded as 3, and so on.
wire type 1 : 64bit double 등은 고정된 64bit 데이터를 지시.
wire type 5 : 32bit형 float 등은 고정된 32bit 데이터를 지시.
wire type 2
Ex) string query = 1, value에 "testing" 문자열 저장
field_number ==> 1
wire_type ==> 2
"testing" 문자열 길이 ==> 7
Encoding 결과 ==> '0A' '07' 74 65 73 74 69 6e 67
message 정의 시 field type을 다른 메시지로도 지정할 수 있다.(메시지간 포함 관계)
int32 a = 150
08 96 01
field num = 1 & wire type = 0 (int32)
==> 00001000 ==> 0x08
150 : 1|0010110
==> 00000001 00010110
==> 00010110 00000001
==> '1'0010110 '0'0000001 ==> 96 01
Text1 c = 3
filed num = 3 & wire type = 2 (embedded Mesgage)
==> 00011_010
첫번째 값을 default value로 사용한다.
enum은 상수를 저장하는 열거형 데이터이며, encoding 하면 const 상수 형태로 저장되고, 각 name / value 별 map이 별도로 지정.
값들은 세미콜론(;)으로 구분. 구분하지 않았을때 에러 발생.
allow_alias 옵션 : 다른 name에 같은 값을 줄 수 있다. 향후 value를 참조할 때는 복수 개의 값이 있을 테니 oneof로 하나만 선정하여 사용.
enum 값을 삭제하거나 주석처리하여 update 시켰다면 다른 사용자가 이 값을 재 사용하게될 수도 있는데, 이는 proto file의 버전이 안맞을 경우 데이터 손상 등의 문제를 일으킬 수 있다.
이를 방지하고 싶다면, value / name을 더이상 접근할 수 없게 reserve. 단, 아래 예제와 같이 reserved 만 선언한다면 error가 리턴되므로 default 값을 고려하여 enum 첫 줄엔 하나 이상의 상수를 선언 필요.
맵의 필드들은 repeated 될 수 없으며, 언어별로 구현 방식이 상이함.
암호화 인증이 필요한 경우 두 가지 메커니즘을 지원
ssl/tls
token
Server Down일때 Client가 요청.
Server down 후 다시 up.
Client timeout이 충분히 커도, 8회 초과시 close.
L4환경에서 failover.
잘 읽었습니다.