필드 번호를 바꿨더니 옛 클라이언트가 조용히 틀린 값을 읽었다 · 바이트 한 줄이 필드 번호를 품고 있다 · 퀴즈
퀴즈: 바이트에는 이름이 없다
문항 6개. 정답과 해설은 풀어 본 뒤에 보여 드립니다.
int32 필드 1 에 150 을 넣으면 `08 96 01` 세 바이트가 된다. 첫 바이트 `08` 이 뜻하는 것은?
- 필드 번호 1, 와이어 타입 0(VARINT) 인 태그
- 메시지의 전체 길이가 8 바이트라는 표시
- 필드 이름 a 의 해시를 한 바이트로 줄인 값
- 값 150 의 상위 바이트를 먼저 쓴 것
옛 파서가 새로 추가된 필드 번호를 만나도 오류 없이 건너뛸 수 있는 근거는?
- 메시지 앞에 필드 개수와 각 길이 표가 있어서
- 새 필드는 항상 메시지 맨 뒤에 붙도록 규칙이 정해져 있어서
- 태그의 와이어 타입이 값의 길이를 알려 주기 때문에
- 파서가 .proto 파일을 런타임에 다시 내려받기 때문에
`string b = 2` 에 "testing" 을 넣으면 `12 07 74 65 …` 로 시작한다. 여기서 `07` 은?
- 필드 2 가 일곱 번째로 직렬화됐다는 순서 번호
- 문자열 페이로드의 바이트 수를 담은 길이 varint
- UTF-8 인코딩 방식을 가리키는 코드 7
- 다음 필드까지 건너뛸 태그의 개수
`int32` 필드에 -1 을 넣으면 10 바이트가 되고 `sint32` 는 1 바이트가 된다. 그 차이를 만드는 것은?
- sint32 는 부호 비트를 태그의 와이어 타입 자리에 옮겨 담기 때문에
- int32 는 값과 무관하게 항상 고정 10 바이트로 정해져 있기 때문에
- sint32 는 값을 절반으로 나눠 저장해 바이트가 줄어들기 때문에
- int32 는 64비트 2의 보수를, sint32 는 ZigZag 값을 varint 로 보내기 때문에
`repeated int32 e = 5` 에 1, 2, 3 을 넣으면 `2a 03 01 02 03` 이 된다. 이 인코딩의 이름과 성질은?
- packed — 태그 하나짜리 LEN 레코드 안에 값이 이어 붙는다
- grouped — SGROUP 과 EGROUP 태그로 값을 감싼다
- indexed — 각 값 앞에 위치 번호가 붙는다
- expanded — 원소마다 태그 `28` 이 반복된다
같은 메시지 객체를 두 번 직렬화한 바이트를 비교해 변경 여부를 판단하는 코드가 위험한 이유는?
- 직렬화할 때마다 타임스탬프 필드가 자동으로 붙기 때문에
- 직렬화 순서와 바이트 출력이 안정적이라는 보장이 없기 때문에
- 두 번째 직렬화부터는 알 수 없는 필드가 버려지기 때문에
- 메시지가 2 GiB 를 넘으면 앞부분만 잘려 나가기 때문에