내 API에 JSON 사용을 중단하고 Protobuf로 바꾼 이유

5 days ago 4

  • 웹 API의 표준으로 자리 잡은 JSON은 읽기 쉽고 유연하지만, 성능과 안정성 면에서 한계가 있음
  • Protobuf(Protocol Buffers)엄격한 타입 정의자동 코드 생성을 통해 데이터 구조를 명확히 보장함
  • 이진 직렬화를 사용해 JSON보다 약 3배 이상 데이터 크기를 줄이고 전송 속도를 향상시킴
  • 서버와 클라이언트가 동일한 .proto 스키마를 공유해 타입 불일치나 수동 검증이 필요 없음
  • 디버깅은 어렵지만, 성능·유지보수성·개발 효율성 측면에서 Protobuf가 현대적 API에 더 적합함

JSON의 보편성과 한계

  • JSON은 사람이 읽기 쉬운 텍스트 포맷으로, 단순한 console.log()만으로도 데이터를 확인할 수 있음
  • 웹과의 완벽한 통합성 덕분에 JavaScript와 백엔드 프레임워크 전반에서 널리 채택됨
  • 필드 추가·삭제·타입 변경이 자유로운 유연성을 제공하지만, 이로 인해 구조 불일치나 오류 발생 가능성 존재
  • 도구 생태계가 풍부해 텍스트 편집기나 curl만으로도 쉽게 다룰 수 있음
  • 그러나 이러한 장점에도 불구하고, 성능과 타입 안정성 면에서는 더 나은 대안이 존재함

Protobuf의 개요

  • Google이 2001년에 개발하고 2008년에 공개한 이진 직렬화 포맷
  • 내부 시스템과 마이크로서비스 간 통신에서 널리 사용됨
  • 종종 gRPC와 함께 사용해야 한다는 오해가 있지만, Protobuf는 독립적으로 HTTP API에서도 활용 가능
  • 초기에는 이진 포맷의 비가시성 때문에 접근성이 낮았으나, 효율성과 안정성 면에서 강점이 큼

강력한 타입 시스템과 코드 생성

  • Protobuf는 .proto 파일을 통해 데이터 구조를 명확히 정의
    • 각 필드는 엄격한 타입, 숫자 식별자, 고정된 이름을 가짐
  • 예시: message User { int32 id = 1; string name = 2; string email = 3; bool isActive = 4; }
  • protoc 명령으로 Dart, TypeScript, Kotlin, Swift, C#, Go, Rust 등 다양한 언어의 자동 코드 생성 지원
  • 생성된 코드로 직렬화(writeToBuffer)와 역직렬화(fromBuffer) 를 수행하며, 수동 검증이나 파싱 불필요
  • 결과적으로 시간 절약유지보수성 향상을 동시에 달성

이진 직렬화의 효율성

  • Protobuf는 텍스트 대신 이진 데이터로 직렬화되어 매우 압축적이고 빠름
  • 동일한 데이터(User 객체)의 크기 비교:
    • JSON: 86바이트 (공백 제거 시 68바이트)
    • Protobuf: 30바이트
  • 효율의 원인:
    • 숫자에 varint 인코딩 사용
    • 텍스트 키 대신 숫자 태그 사용
    • 공백 및 불필요한 구문 제거
    • 선택적 필드 최적화
  • 결과적으로 대역폭 절감, 응답 속도 향상, 모바일 데이터 절약, 사용자 경험 개선 효과

Dart 기반 Protobuf API 예시

  • shelf 패키지를 이용해 간단한 HTTP 서버를 구성하고, User 객체를 Protobuf로 반환
  • 서버 코드 핵심:
    • User() 객체를 생성 후 writeToBuffer()로 직렬화
    • 응답 헤더에 'content-type': 'application/protobuf' 지정
  • 클라이언트는 http 패키지와 user.pb.dart를 사용해 Protobuf 데이터를 직접 디코딩
  • 서버와 클라이언트가 동일한 .proto 스키마를 공유하므로 데이터 구조 불일치가 발생하지 않음
  • 동일한 방식이 Go, Rust, Kotlin, Swift, C#, TypeScript 등에서도 동일하게 적용 가능

JSON의 남은 장점

  • Protobuf는 스키마 없이 의미를 해석하기 어려움
    • 필드 이름 대신 숫자 식별자만 표시되어 사람이 읽기 어려움
  • 예시 비교:
    • JSON: { "id": 42, "name": "Alice" }
    • Protobuf: 1: 42, 2: "Alice"
  • 따라서 Protobuf는:
    • 전용 디코딩 도구 필요
    • 스키마 관리 및 버전 관리 필수
  • 그럼에도 불구하고, 성능과 효율성의 이점이 훨씬 큼

결론

  • Protobuf는 성숙하고 고성능의 직렬화 기술로, 공개 API에서도 충분히 활용 가능
  • gRPC 없이도 일반 HTTP API에서 독립적으로 동작
  • 성능, 견고성, 오류 감소, 개발 효율성을 모두 향상시키는 도구
  • 차세대 프로젝트에서 Protobuf를 도입할 가치가 충분함

Read Entire Article