Protobuf 란?

HEETAE HEO·2023년 3월 7일
0
post-thumbnail

오늘은 Protobuf에 대해서 설명하는 글을 작성하려고 합니다.

Protobuf(Protocol Buffers)의 경우 사내 개발팀 내에서 이야기가 나오게 되었고 우리도 해당 기술의 도입을 검토할 필요가 있을 것 같다! 라는 이야기가 나오게 되어 공부하게 되었습니다.

Protobuf란?

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)

다음과 같은 방식으로 프로젝트에서 데이터 구조를 효율적으로 정의하고, 전송하거나 저장할 수 있습니다. 그렇게 되면 애플리케이션의 성능은 향상되며, 코드의 명확성과 유지 관리성을 높일 수 있습니다.

Protobuf의 세부적 사용 시나리오

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를 사용하면 이러한 메시지의 구조를 효율적으로 정의하고, 송수신 시 필요한 대역폭을 줄일 수 있습니다. 이를 통해 분산 시스템의 성능과 안정성을 향상시킬 수 있습니다.

Android 개발에서의 장단점

장점

  1. 효율적인 데이터 전송 : Protobuf는 이진 포맷을 사용하여 데이터를 압축하고, 송수신시 필요한 대역폭과 저장 공간을 줄입니다. 이로 인해 통신 비용이 절감되고, 애플리케이션의 반응 속도가 개선됩니다.

  2. 강력한 타입 안정성 : Protobuf는 명시적인 타입 정보를 포함하므로, 데이터의 정확성과 일관성을 유지하면서 개발자의 실수를 최소화할 수 있습니다.

  3. 버전 호환성: 필드 번호를 사용하여 데이터 구조를 식별하므로, 기존 코드를 수정하지 않고도 새로운 필드를 추가하거나 제거할 수 있습니다. 이를 통해 소프트웨어의 확장성과 유연성이 향상됩니다.

  4. 다양한 언어 지원 : Protobuf는 여러 프로그래밍 언어를 지원하므로, 서로 다른 플랫폼 및 언어 간의 통신이 용이해집니다. 이로 인해 시스템 간의 상호운용성이 향상되며, 개발자의 생산성이 증가합니다.

  5. 빠른 직렬화/역직렬화: Protobuf는 빠른 직렬화 및 역직렬화를 제공하므로, 애플리케이션의 성능을 향상시킬 수 있습니다.

단점

  1. 가독성 : Protobuf는 이진 포맷을 사용하기 때문에, Json과 같은 텍스트 기반 포맷에 비해 가독성이 떨어집니다. 이로 인해 디버깅이 어려울 수 있습니다.

  2. 초기 설정 복잡성 : Protobuf를 사용하려면 플러그인을 설정해주고, .proto 파일으 작성해야합니다. 이 과정이 초기 설정 시간을 늘리고, 개발자에게 추가적인 학습 곡선을 제공할 수 있습니다.

  3. 추가적인 라이브러리 의존성 : Protobuf를 사용하려면 관련 라이브러리를 포함해야 합니다. 이로 인해 애플리케이션의 크기가 증가할 수 있습니다.

정리

효율적인 데이터 전송, 다양한 언어 지원 및 강력한 타입 안정성 및 성능이 있지만 여러 문제점(가독성 및 디버깅의 어려운, 추가적인 라이브러리 의존성, JSON과의 호환성)이 있기에 현업에서의 사용률이 상대적으로 낮은게 아닐까 생각이 됩니다.

하지만 대량의 데이터를 주고 받으며 이로인해 버벅임과 같은 사용자 환경에 불편함을 줄 수 있는 상황이라면 충분히 고려되고 반영될만한 데이터 포맷 형식이라고 생각이 듭니다.

References

https://proandroiddev.com/how-to-setup-your-android-app-to-use-protobuf-96132340de5c
https://protobuf.dev/getting-started/kotlintutorial/

profile
Android 개발 잘하고 싶어요!!!

0개의 댓글