
Protobuf vs JSON 장단점 정리 — 압축을 켜면 크기 이점이 0~35%로 줄어든다
Protobuf가 JSON보다 빠르고 작은 건 사실이다. 직렬화는 3~6배 빠르고 비압축 크기는 절반 수준이다. 그런데 gzip을 켜는 순간 이야기가 달라진다. 동종 레코드 100개 구간에서는 gzip JSON이 오히려 더 작았다. 어떤 경우에 무엇을 써야 하는지 실측과 함께 정리했다.
"JSON 쓰지 말고 Protobuf 써라, 훨씬 빠르고 작다."
개발자 커뮤니티에서 자주 도는 말이다. 절반은 맞고 절반은 조건이 빠져 있다. 빠진 조건이 하필 대부분의 서비스가 이미 켜 두고 있는 것, 압축이다.
숫자부터 보고 시작하자.

먼저, 소문이 맞는 부분
속도는 Protobuf가 확실히 빠르다.
Go에서 흔한 사용자 레코드 하나를 직렬화한 벤치마크를 보면 Protobuf가 약 228 ns/op, JSON이 약 1,340 ns/op 로 6배 가까이 차이가 난다. 일반적으로는 3배 정도로 이야기되고, gzip을 씌운 JSON과 비교하면 직렬화에서 5배 이상 벌어진다. 역직렬화는 메시지가 작을 때는 비슷하고, 커지면 Protobuf가 3배쯤 앞선다.
압축하지 않은 크기도 Protobuf가 작다.
- 102바이트짜리 minified JSON 사용자 레코드 → Protobuf로는 약 51바이트
- 같은 데이터로 잰 실측에서 JSON 329KB vs Protobuf 154KB
보통 raw JSON 대비 50~90% 작다고 본다. 여기까지만 보면 소문이 맞다.
그런데 압축을 켜면
문제는 실무에서 raw JSON을 그대로 쏘는 경우가 드물다는 것이다. 웬만한 서버는 gzip이나 brotli를 켜 둔다.
19가지 페이로드 형태를 gzip·zstd·brotli 세 가지 압축기로 돌린 실험 결과가 흥미롭다. 동종 레코드 100개를 담은 페이로드에서 이런 숫자가 나왔다.
| 형식 | 크기 |
|---|---|
| gzip JSON | 1,639 바이트 |
| gzip Protobuf | 1,690 바이트 |
Protobuf가 오히려 3.1% 더 컸다. 저자는 대략 동종 레코드 100개 근처에서 gzip JSON이 Protobuf를 따라잡는다고 정리했다.
전체적으로도 완전히 압축된 상태에서 Protobuf의 크기 이점은 대체로 0~35% 수준으로 축소된다.
왜 압축이 격차를 좁히나
이유는 단순하다. JSON은 압축기가 가장 좋아하는 형태다.
{"order_id":1,"user_id":7,"amount":1000}
{"order_id":2,"user_id":9,"amount":2500}
"order_id":, "user_id": 가 레코드마다 그대로 반복된다. gzip이 쓰는 LZ77 계열 알고리즘은 이렇게 반복되는 바이트열을 "앞에서 몇 바이트 떨어진 곳에 있는 그것과 같다"는 짧은 참조로 바꾼다. 필드 이름이 백 번 나와도 실제로 저장되는 건 사실상 한 번이다.
반대로 Protobuf는 필드 이름을 아예 보내지 않는다. 이미 군더더기를 걷어낸 바이트라서 분포가 거의 균등하고, 압축기가 더 짜낼 여지가 적다.
즉 JSON은 압축 전에 뚱뚱하고 압축이 잘 되는 형식이고, Protobuf는 압축 전에 날씬하지만 더 줄지 않는 형식이다.

그래도 Protobuf가 이기는 자리
압축을 켜도 Protobuf가 뚜렷하게 앞서는 경우가 있다.
- 희소 필드: 21개 필드 중 3개만 채워진 페이로드에서 JSON은
null을 다 실어 gzip 후 104바이트, Protobuf는 31바이트였다. 70% 절감이다. Protobuf는 값이 없는 필드를 아예 쓰지 않는다. - 작은 메시지: 메시지당 고정 오버헤드가 상대적으로 크게 작용한다.
- 숫자 배열: packed 인코딩으로 정수를 촘촘히 담는다. JSON은 숫자를 문자열로 적는다.
- 불린이 많은 데이터, 카디널리티 낮은 enum: Protobuf는 정수 하나, JSON은
"PENDING"같은 문자열이다.
정리하면 레코드가 균일하게 반복될수록 JSON이 따라붙고, 필드가 듬성듬성하거나 숫자·불린 위주일수록 Protobuf가 벌린다.
Protobuf가 진짜 파는 것
여기까지 오면 선택 기준이 바뀐다. 크기 때문에 Protobuf를 고르는 건 생각보다 근거가 약하다. 실제로 남는 이유는 두 가지다.
하나는 파싱 속도. 압축률과 무관하게 CPU 시간은 확실히 아낀다. 트래픽이 크면 이게 곧 서버 비용이다.
다른 하나는 스키마다. .proto 파일이 곧 서비스 간 계약이 된다. 필드 타입이 강제되고, 언어별 코드가 자동 생성되고, 컴파일 시점에 불일치가 잡힌다. JSON에서는 "그 필드 문자열이었나 숫자였나"를 런타임에 알게 되는 일이 흔하다.
치러야 할 대가
Protobuf를 도입하면 잃는 것도 분명하다.
디버깅이 어려워진다. 바이너리라 눈으로 못 읽는다. 로그에 찍어도 의미가 없고, 스키마 없이는 해독 자체가 안 된다. curl로 찔러 보고 눈으로 확인하던 흐름이 사라진다.
브라우저에서 불편하다. JS는 Protobuf를 기본 지원하지 않는다. gRPC-Web 같은 계층이나 프록시가 필요하고 번들 크기도 늘어난다.
필드 번호가 곧 정체성이다. .proto에서 = 1, = 2 로 붙은 번호가 실제 식별자다. 이름은 바꿔도 되지만 번호를 바꾸면 예전 메시지가 엉뚱한 필드로 파싱된다. 에러가 나면 차라리 다행이고, 타입이 우연히 맞으면 조용히 잘못된 값이 들어간다. 필드 삭제 시 reserved 처리가 규율로 자리 잡아야 하는 이유다.
생태계가 JSON만큼 넓지 않다. 외부 파트너 연동이나 서드파티 도구에서는 여전히 JSON이 기본값이다.
그래서 언제 무엇을 쓰나
| 상황 | 선택 |
|---|---|
| 공개 REST API, 외부 파트너 연동 | JSON |
| 브라우저가 직접 호출하는 엔드포인트 | JSON |
| 스키마가 자주 바뀌는 초기 제품·MVP | JSON |
| 단순 CRUD, 트래픽 적음 | JSON |
| 내부 마이크로서비스 간 대량 통신 | Protobuf |
| 모바일 등 대역폭이 비싼 클라이언트 | Protobuf |
| 팀이 여럿이라 계약을 강제해야 할 때 | Protobuf |
| 스트리밍·양방향 통신(gRPC) | Protobuf |
| 희소 필드·숫자 배열 위주 페이로드 | Protobuf |
한 가지 덧붙이면, 둘 중 하나만 골라야 하는 것도 아니다. 내부 통신은 gRPC로 두고 바깥 경계에는 gRPC-Gateway 같은 걸 세워 JSON REST로 노출하는 구성이 흔하다.
두 형식의 비용 구조가 서로 다르다는 점을 짚고 싶다. JSON의 비용은 런타임에 발생한다. 요청마다 파싱 CPU를 조금씩 더 쓰고 바이트를 조금 더 흘려보낸다. Protobuf의 비용은 개발 시점에 발생한다. 스키마를 관리하고, 코드젠을 빌드에 엮고, 필드 번호 규율을 지키고, 디버깅 도구를 새로 갖춰야 한다. 그래서 트래픽이 적은 서비스가 Protobuf를 도입하면 아끼는 런타임 비용은 체감되지 않는데 개발 비용만 고스란히 남는다. 반대로 초당 수만 건을 처리하는 내부 서비스라면 그 CPU 차이가 서버 대수로 환산된다. 결국 "무엇이 더 좋은 기술인가"가 아니라 "우리 트래픽 규모에서 어느 쪽 비용이 더 비싼가"의 문제다. 그리고 이건 바꿔 말하면, 성능 때문에 Protobuf를 검토하고 있다면 먼저 압축이 제대로 켜져 있는지, 병목이 정말 직렬화인지 프로파일링부터 해 보라는 뜻이기도 하다. 압축을 안 켠 채로 Protobuf를 도입하면 압축만 켜도 얻었을 이득을 형식 교체의 성과로 오해하기 쉽다.
정답은 "Protobuf가 좋다"도 "JSON이면 충분하다"도 아니다. 크기 때문이라면 근거가 약하고, 파싱 CPU와 타입 계약 때문이라면 근거가 단단하다. 그 둘이 지금 우리 팀에 얼마나 아픈 문제인지가 기준이다.
여러분 팀은 어느 쪽인가요? Protobuf로 옮겨 본 경험이 있다면 실제로 체감된 이득이 속도였는지, 아니면 스키마 관리 쪽이었는지 궁금합니다.
📎 출처: 원문 보기
- gauravsarma1992.medium.comhttps://gauravsarma1992.medium.com/when-does-compressed-protobuf-actually-beat-compressed-json-be6917c79f82
- protobuf.devhttps://protobuf.dev/
- jsonic.iohttps://jsonic.io/guides/json-protobuf
- zuplo.comhttps://zuplo.com/learning-center/protobuf-vs-json-api-serialization
댓글 0
댓글을 불러오는 중…








