자바를 통해서 api 작업을 한다면 직렬화, 역직렬화는 매우 중요한 포인트 중 하나이다. 데이터를 주고 받거나 데이터를 저장할 때처럼 다양한 상황에 꼭 필요한 요소이기도 하면서 비용이 정말 큰 프로세스이기도 하기 때문이다. 하지만 우리는 대부분의 경우 작업의 편의성을 위해서 따로 데이터를 해석할 필요가 없는 JSON같은 문자열 데이터를 쓰곤 한다.
우리 팀도 JSON을 이용해서 자바 직렬화/역직렬화를 사용하고 있었다. 그러던 중 매우 크기가 큰 데이터를 주기적으로 주고 받는 api를 구현해야할 상황이 생겼다. (리스트의 크기 약 2000개 이상…) 그리고 한 팀원분이 protocol buffers(이하 protobuf) 를 쓰는게 어떻냐는 제안을 하면서 시작됐다.
protobuf란 이진 직렬화 프로토콜 중 하나로 구글에서 개발한 언어 및 플랫폼 중립적인 직렬화 메커니즘이다. 구조화된 데이터를 다루는 데에 사용된다. 자바 외에도 C++, C#, Dart, Go, Kotlin, Objective-C, Python 및 Ruby 등에서도 사용 가능하다.
프로토콜 버퍼는 효율적인 이진 직렬화
로 인해 대량의 데이터 처리에 강하다. 같은 이진 직렬화를 사용하는 Apache Avro와 비교해도 일반적으로 높은 압축률과 성능을 보여준다.
implementation 'com.google.protobuf:protobuf-java:3.24.3'
syntax = "proto3";
// 해당 proto 파일로 컴파일된 자바 파일이 위치할 곳
option java_package = "com.example.tutorial.person";
message Request {
repeated Person positions = 1;
}
message Person {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
}
brew install protobuf
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/person.proto
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Bean
public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter()
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new Jackson2HttpMessageConverter());
converters.add(new ProtobufHttpMessageConverter());
super.addDefaultHttpMessageConverters(converters);
}
private void callProtobuf(PathRequest request, boolean compression) {
RestTemplate restTemplate;
HttpHeaders headers = new HttpHeaders();
restTemplate = new RestTemplate(List.of(new ProtobufHttpMessageConverter()));
headers.setContentType(ProtobufHttpMessageConverter.PROTOBUF);
HttpEntity<PathRequest> httpEntity = new HttpEntity<>(request, headers);
restTemplate.exchange("http://localhost:8080/test/protobuf", HttpMethod.POST, httpEntity, Void.class);
}
@SneakyThrows
@PostMapping(value = "/test/path/protobuf", consumes = {"application/x-protobuf"})
@ResponseStatus(HttpStatus.NO_CONTENT)
public void pingPong(@RequestBody PathRequest request) {
log.info("[protobuf] recved request len: {} ", request.getSerializedSize());
}
option java_package
로 지정했던 경로에 생성된다.
저는 아직도 못 써봤는데, 말로만 듣던 protobuf를 드디어 써보셨군요
내용을 자세하게 잘 정리해 놓으셔서 실제 사용하는것처럼 느껴질 정도네요
특히 후기의 좋았던점, 아쉬웠던점이 실제 적용해본 사람의 느낌이 있어서 좋았네요
그리고 아쉽지만 여기도 옥의티가 하나 있네요
"네트워크 존성" --> "네트워크 의존성" 인듯 하네요