오늘은 Protobuf에 대해서 설명하는 글을 작성하려고 합니다.
Protobuf(Protocol Buffers)의 경우 사내 개발팀 내에서 이야기가 나오게 되었고 우리도 해당 기술의 도입을 검토할 필요가 있을 것 같다! 라는 이야기가 나오게 되어 공부하게 되었습니다.
Protocol Buffers는 구글에서 개발한 이진 직렬화 포맷입니다. Protobuf 플랫폼 및 언어에 독립적이며, 다양한 언어와 시스템에서 데이터를 효율적으로 전송하기 위해 사용됩니다. 주요 장점은 작은 메시지 크기, 빠른 직렬화/역직렬화 속도 및 강력한 타입 안정성을 제공한다는 것입니다. 추가적인 이점은 글 후반에 한번 더 작성하겠습니다.
우선 프로젝트에서 Protobuf를 사용하려면
1. Project의 gradle 작성
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.17'
}
}
2. 의존성 추가
앱 모듈의 build.gradle 파일에 Protobuf 플러그인 및 라이브러리 의존성을 추가해줍니다.
apply plugin: 'com.google.protobuf'
dependencies {
implementation 'com.google.protobuf:protobuf-javalite:3.17.3'
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.17.3"
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option 'lite'
}
}
}
}
}
3. 프로토콜 버퍼 스키마 파일 작성
프로젝트 내에서 .proto 파일을 작성하여 원하는 데이터 구조를 정의합니다. 예를 들어, 다음과 같은 파일이 있을 수 있습니다.
syntax = "proto3";
package com.example.protobuf;
message UserProfile {
int32 id = 1;
string name = 2;
string email = 3;
}
4. proto 파일 빌드
프로젝트를 빌드하면 .proto 파일에 대한 Java 코드가 자동으로 생성됩니다. 이렇게 생성된 코드를 사용하여 데이터를 직렬화하거나 역직렬화할 수 있습니다.
5. 생성된 Java 코드 사용
앱에서 생성된 Java 코드를 사용하여 Protobuf 객체를 생성, 수정, 직렬화 및 역직렬화할 수 있습니다.
// 객체 생성 및 수정
val userProfile = UserProfile.newBuilder()
.setId(1)
.setName("John Doe")
.setEmail("john.doe@example.com")
.build()
// 객체 직렬화
val byteArray = userProfile.toByteArray()
// 객체 역직렬화
val deserializedUserProfile = UserProfile.parseFrom(byteArray)
다음과 같은 방식으로 프로젝트에서 데이터 구조를 효율적으로 정의하고, 전송하거나 저장할 수 있습니다. 그렇게 되면 애플리케이션의 성능은 향상되며, 코드의 명확성과 유지 관리성을 높일 수 있습니다.
1. 데이터 저장 및 로딩
Protobuf를 사용하여 애플리케이션의 설정, 사용자 데이터, 게임 데이터 등을 저장 및 로딩할 수 있습니다. 이를 통해 파일의 크기를 줄이고, 빠르게 데이터를 읽고 쓸 수 있습니다.
// UserProfile 객체를 파일에 저장
fun saveUserProfile(context: Context, userProfile: UserProfile) {
val fileOutputStream = context.openFileOutput("user_profile.pb", Context.MODE_PRIVATE)
userProfile.writeTo(fileOutputStream)
fileOutputStream.close()
}
// 파일에서 UserProfile 객체를 로딩
fun loadUserProfile(context: Context): UserProfile? {
return try {
val fileInputStream = context.openFileInput("user_profile.pb")
val userProfile = UserProfile.parseFrom(fileInputStream)
fileInputStream.close()
userProfile
} catch (e: FileNotFoundException) {
null
}
}
2. 네트워크 통신
Protobuf를 사용하여 클라이언트와 서버 간에 데이터를 주고받을 수 있습니다. 이를 통해 통신 효율성을 높이고, 다양한 언어 및 플랫폼에서 작성된 서버와 클라이언트를 쉽게 통합할 수 있습니다.
// 서버로부터 UserProfile 리스트를 받아오는 예제 (Retrofit 사용)
interface UserService {
@POST("/get_user_profiles")
suspend fun getUserProfiles(@Body request: UserProfileRequest): Response<UserProfileList>
}
// UserProfileRequest 및 UserProfileList는 .proto 파일에서 정의한 메시지 타입입니다.
3. 로그 데이터 전송 및 분석
Protobuf를 사용하여 애플리케이션의 로그 데이터를 구조화하여 보낼 수 있습니다. 이를 통해 로그 데이터의 크기를 줄이고, 로그 서버와의 통신 효율성을 높일 수 있습니다. 또한 구조화된 로그 데이터를 쉽게 분석하고 처리할 수 있습니다.
4. 분산 시스템
분산 시스템에서는 여러 노드가 서로 메시지를 주고받아야 합니다. Protobuf를 사용하면 이러한 메시지의 구조를 효율적으로 정의하고, 송수신 시 필요한 대역폭을 줄일 수 있습니다. 이를 통해 분산 시스템의 성능과 안정성을 향상시킬 수 있습니다.
효율적인 데이터 전송 : Protobuf는 이진 포맷을 사용하여 데이터를 압축하고, 송수신시 필요한 대역폭과 저장 공간을 줄입니다. 이로 인해 통신 비용이 절감되고, 애플리케이션의 반응 속도가 개선됩니다.
강력한 타입 안정성 : Protobuf는 명시적인 타입 정보를 포함하므로, 데이터의 정확성과 일관성을 유지하면서 개발자의 실수를 최소화할 수 있습니다.
버전 호환성: 필드 번호를 사용하여 데이터 구조를 식별하므로, 기존 코드를 수정하지 않고도 새로운 필드를 추가하거나 제거할 수 있습니다. 이를 통해 소프트웨어의 확장성과 유연성이 향상됩니다.
다양한 언어 지원 : Protobuf는 여러 프로그래밍 언어를 지원하므로, 서로 다른 플랫폼 및 언어 간의 통신이 용이해집니다. 이로 인해 시스템 간의 상호운용성이 향상되며, 개발자의 생산성이 증가합니다.
빠른 직렬화/역직렬화: Protobuf는 빠른 직렬화 및 역직렬화를 제공하므로, 애플리케이션의 성능을 향상시킬 수 있습니다.
가독성 : Protobuf는 이진 포맷을 사용하기 때문에, Json과 같은 텍스트 기반 포맷에 비해 가독성이 떨어집니다. 이로 인해 디버깅이 어려울 수 있습니다.
초기 설정 복잡성 : Protobuf를 사용하려면 플러그인을 설정해주고, .proto 파일으 작성해야합니다. 이 과정이 초기 설정 시간을 늘리고, 개발자에게 추가적인 학습 곡선을 제공할 수 있습니다.
추가적인 라이브러리 의존성 : Protobuf를 사용하려면 관련 라이브러리를 포함해야 합니다. 이로 인해 애플리케이션의 크기가 증가할 수 있습니다.
효율적인 데이터 전송, 다양한 언어 지원 및 강력한 타입 안정성 및 성능이 있지만 여러 문제점(가독성 및 디버깅의 어려운, 추가적인 라이브러리 의존성, JSON과의 호환성)이 있기에 현업에서의 사용률이 상대적으로 낮은게 아닐까 생각이 됩니다.
하지만 대량의 데이터를 주고 받으며 이로인해 버벅임과 같은 사용자 환경에 불편함을 줄 수 있는 상황이라면 충분히 고려되고 반영될만한 데이터 포맷 형식이라고 생각이 듭니다.
https://proandroiddev.com/how-to-setup-your-android-app-to-use-protobuf-96132340de5c
https://protobuf.dev/getting-started/kotlintutorial/
잘 읽고 갑니다 (꾸벅)