Protobuf — バイナリデータ形式と動作原理

著者: IT Sectr 公開日: 2026-03-08 読了時間: 8 分

Protocol Buffers (Protobuf) は構造化データのためのバイナリシリアライゼーション形式であり、Google がサービス間の効率的な情報交換のために開発しました。この形式では .proto ファイルでスキーマを事前に定義する必要があり、そこから様々な言語のコードが生成されます。Google の公式ドキュメントによると、Protobuf は JSON より 3-10 倍小さなメッセージサイズを実現します。Protobuf は gRPC、Google Maps および数千の内部サービスで使用されています。

ポイント

  • Protobuf — コンパクトなデータ表現でシリアライゼーションを行う Google のバイナリ形式
  • .proto スキーマ — コードにコンパイルされるデータ構造の正確な型付き説明
  • パフォーマンス — JSON より 3-10 倍高速かつコンパクトなシリアライゼーション
  • 下位互換性 — 既存クライアントを破さずにスキーマを進化
  • gRPC — マイクロサービスにおける Protobuf の主要トランスポート技術

Protocol Buffers とは?

Protocol Buffers は Google が開発した構造化データのシリアライゼーションメカニズムで、JSON や XML と似ていますが、根本的な違いがあります:データはバイナリ形式でエンコードされます。つまり、Protobuf メッセージは肉眼で読むことはできませんが、少ないスペースでテキストベースのものより高速に処理できます。

Protobuf は、サービス間のデータ交換におけるパフォーマンス問題を解決するために Google 内部で作られました。2008年にこの技術はオープンソースプロジェクトとなり、C++、Java、Python、Go、JavaScript、Kotlin、Swift、Dart など多くの言語をサポートしています。2016年にリリースされた proto3 バージョンは構文を簡素化し、さらに多くの言語のサポートを追加しました。

Protobuf と JSON の主な違いは、データ交換を開始する前にスキーマを定義する必要があることです。スキーマファイル (.proto) はメッセージ構造を記述します:フィールド、型、および固有のフィールド番号。このスキーマから、protoc コンパイラがシリアライゼーションとデシリアライゼーションのためのターゲット言語のクラスを生成します。

Protobuf エコシステム

  • gRPC — デフォルトで Protobuf を使用する高パフォーマンス RPC フレームワーク
  • protoc — .proto スキーマをさまざまなプログラミング言語のコードに変換するコンパイラ
  • Google API — 大部分の Google 公開 API は Protobuf を使用
  • Envoy Proxy — 設定およびデータ交換に Protobuf を使用

Protobuf のアーキテクチャ

Protobuf のアーキテクチャは、スキーマ定義言語 (.proto)、protoc コンパイラ、および特定の言語用のランタイムライブラリの 3 つの主要コンポーネントで構成されます。開発者は .proto ファイルでデータ構造を記述し、コンパイルを実行し、このデータを操作するための完成したクラスを得られます。

Protobuf メッセージの各フィールドには固有の番号(フィールド番号)があります。これは順列番号ではなく、バイナリ形式でフィールドを識別するためのタグです。1~15 の番号は 1 バイトで、16~2047 は 2 バイトでエンコードされます。そのため、使用頻度の高い重要なフィールドはサイズ最適化のために 1~15 の番号を付けるべきです。

Protobuf のデータタイプ

Protobuf は、スカラー (int32, int64, float, double, bool, string, bytes)、統括 (enum)、複合 (message)、および特殊 (oneof, map) など幅広いタイプをサポートしています。各タイプには、対応する使用ケースに最適化された特定のバイナリ表現があります。

.proto 型 C++ 型 Java/Kotlin 説明
double double double 64ビット浮動小数点数
float float float 32ビット浮動小数点数
int32 int32 int 32ビット、可変長エンコーディング
int64 int64 long 64ビット、可変長エンコーディング
string string String UTF-8 文字列
bytes string ByteString 任意のバイト列
bool bool boolean true / false

バイナリ形式のメリット

Protobuf は、テキストベースの形式に比べて、メッセージサイズ、シリアライゼーション速度、および懈密な型付けの 3 つの主要な利点を提供します。高負荷システムやトラフィックの制限されたモバイルアプリでは、これらの利点が重要になります。

Protobuf のバイナリ表現は、数値に可変長エンコーディング (Varint) を使用します:小さな数値は 1 バイト、大きな数値は最大 10 バイトです。これにより、JSON や XML でテキスト文字列として数十バイトを占める識別子フラグカウンタを効率的にエンコードできます。例えば、150 という数値は Protobuf で 2 バイト、JSON で 3 バイト (“150” というテキスト)、XML で 3 バイト + タグを占めます。

もう一つの利点は下位互換性です。スキーマに新しいフィールドを追加しても、古いクライアントは破壊されません:不明なフィールドを無視するだけです。フィールドを削除するには、将来の競合を避けるためにその番号を予約するだけでよいです。

.proto スキーマの定義

.proto スキーマは、専用言語でデータ構造を記述します。ファイルは、構文(proto3)、パッケージ、およびインポート依存関係の指定から始まります。各メッセージは、フィールドを伴うキーワード message で定義され、各フィールドには型、名前、固有番号があります。

良いスキーマの実践:頻繁に使用されるフィールドには 1~15 のフィールド番号、意味のある名前、関連するフィールドを別の message にまとめること、複数のオプションのうちの 1 つしか持てないフィールドに oneof を使用すること。

protobuf
syntax = "proto3";

package mobileapp;

message User {
  string user_id = 1;
  string name = 2;
  string email = 3;
  int32 age = 4;
  UserRole role = 5;
  repeated string tags = 6;
  map<string, string> metadata = 7;
}

enum UserRole {
  USER_ROLE_UNSPECIFIED = 0;
  USER_ROLE_USER = 1;
  USER_ROLE_ADMIN = 2;
  USER_ROLE_MODERATOR = 3;
}

ネスト深げメッセージ

メッセージはネスト深げにできます:Profile 型のprofileフィールドは内部にユーザーデータを保持します。ネスト深げのサポートにより、定義を複製せずに複雑な階層構造を記述できます。

protobuf
syntax = "proto3";

package mobileapp;

message Order {
  string order_id = 1;
  repeated OrderItem items = 2;
  double total_price = 3;
  PaymentInfo payment = 4;
}

message OrderItem {
  string product_id = 1;
  string title = 2;
  int32 quantity = 3;
  double price = 4;
}

message PaymentInfo {
  string method = 1;
  string transaction_id = 2;
  double amount = 3;
}

.proto からのコード生成

protoc コンパイラは .proto ファイルをターゲット言語のソースコードに変換します。Kotlin/Java では --java_out パラメータが使用され、Swift では --swift_out(Apple Swift Protobuf プラグインを通じて)、Dart では --dart_out が使用されます。生成されたクラスには、メッセージ構築のためのビルダーメソッドとシリアライゼーション/デシリアライゼーションメソッドが含まれています。

Android で Protobuf を使用するには、Gradle で com.google.protobuf プラグインバージョン 0.9+ を使用します。プラグインを追加し、.proto ファイルを指定すると、ビルド自動的にアプリで使用できる Kotlin クラスを生成します。

kotlin
import com.google.protobuf.kotlin.toByteString
import com.example.mobileapp.UserOuterClass.User

fun createUser(): User {
    return User.newBuilder()
        .setUserId("usr_001")
        .setName("IT Sectr")
        .setEmail("team@itsectr.com")
        .setAge(5)
        .setRole(UserOuterClass.UserRole.USER_ROLE_ADMIN)
        .addTags("mobile")
        .addTags("backend")
        .build()
}

fun serializeAndDeserialize(user: User): User {
    // バイナリ形式へのシリアライゼーション
    val bytes = user.toByteArray()

    // バイナリ形式からのデシリアライゼーション
    return User.parseFrom(bytes)
}

Protobuf の使用例

Protobuf は、マイクロサービスアーキテクチャやモバイルアプリで特に効果的です。よくあるシナリオを考えてみましょう:モバイルアプリが gRPC を通じてサーバーから商品リストを受け取ります。Protobuf メッセージには、識別子、名前、価格、カテゴリなどの商品情報が含まれています。バイナリ形式は JSON と比較してレスポンスサイズを 5-8 倍縮小します。

Kotlin による gRPC サービス

サーバーサイドの Protobuf を使用した gRPC サービスの例。サービスは GetProducts RPC メソッドを宣言し、ページネーションパラメータを含むリクエストを受け入れ、商品リストを返します。Kotlin の実装は、リクエストとレスポンスを操作するために生成されたクラスを使用します。

kotlin
import com.example.mobileapp.ProductServiceGrpcKt
import com.example.mobileapp.ProductOuterClass.Product
import com.example.mobileapp.ProductOuterClass.GetProductsRequest
import com.example.mobileapp.ProductOuterClass.GetProductsResponse

class ProductService : ProductServiceGrpcKt.ProductServiceCoroutineImplBase() {

    override suspend fun getProducts(
        request: GetProductsRequest
    ): GetProductsResponse {
        val products = fetchProductsFromDb(
            page = request.page,
            limit = request.limit
        )

        return GetProductsResponse.newBuilder()
            .addAllProducts(products)
            .setTotalCount(products.size)
            .build()
    }
}

Android プロジェクトでの Protobuf 設定

Android プロジェクトでの Protobuf 設定は、com.google.protobuf Gradle プラグインを通じて行います。このプラグインは、ビルド中に自動的に protoc コンパイラを実行し、.proto ファイルから Kotlin クラスを生成します。使用するには、プロジェクトレベルの build.gradle にプラグインを追加し、アプリモジュールに適用する必要があります。

Gradle を設定した後、.proto ファイルを src/main/proto ディレクトリに置きます。protoc コンパイラは各ビルドでこれらを処理し、アプリコードで使用できる Kotlin クラスを生成します。他のプロジェクトライブラリとの依存関係競合を避けるために、protobuf および protoc のバージョンを正しく指定することが重要です。

iOS プロジェクトでは、CocoaPods または Swift Package Manager を通じて Protobuf を接続します。Swift Protobuf プラグインは、Codable プロトコルに準拠した Swift 構造体を自動生成します。Flutter の Dart プロジェクトでは、protobuf パッケージが使用され、コンパイルは dart run protoc_plugin で行います。

よくある質問

Protobuf と JSON の違いは?

Protobuf は必須スキーマを持つバイナリ形式で、JSON より 3-10 倍コンパクトです。JSON はテキストベースで人間が読め、スキーマが不要です。Protobuf は高速にシリアライズ・デシリアライズできますが、.proto ファイルのコンパイルが必要です。JSON はデバッグが容易で事前設定が不要です。

protoc コンパイラをインストールする方法は?

ご利用のプラットフォームに応じた protobuf の GitHub リリースからprotocをダウンロードしてください。macOS の場合は、brew install protobuf でインストールできます。Windows の場合は zip アーカイブをダウンロードし、protoc.exe を PATH に追加します。Android/Kotlin の場合は、com.google.protobuf Gradle プラグインを使用します。これはビルド中に自動的にコンパイルを実行します。

gRPC とは何か、Protobuf との関係は?

gRPC は Google による高パフォーマンス RPC フレームワークで、インターフェース定義言語 (IDL) およびシリアライゼーション形式として Protobuf を使用します。gRPC は .proto ファイルでサービスと RPC メソッドを定義し、クライアントとサーバーのコードを生成し、ストリーミングおよびバイナリプロトコルをサポートします。

Protobuf はどのような言語をサポートしていますか?

Google が公式にサポート: C++、Java、Kotlin、Python、Go、Ruby、C#、PHP、JavaScript、Objective-C、Swift、Dart。コミュニティは Rust、TypeScript、Scala、Lua などの言語のサポートを開発しています。モバイル開発には、Kotlin/Java(Android)および Swift/Objective-C(iOS)が利用可能です。

スキーマの下位互換性を確保する方法は?

Protobuf は次のルールで下位互換性をサポートしています:フィールド番号を変更しない、フィールドを削除しない (reserved を使用)、新しい番号で新しいフィールドを追加する。古いクライアントは不明なフィールドを無視し、新しいクライアントは不充の古いフィールドにデフォルト値を取得します。

まとめ

  • Protocol Buffers — 必須データスキーマを持つ Google のバイナリシリアライゼーション形式
  • メッセージサイズ Varint エンコーディングにより JSON より 3-10 倍小さい
  • 速度 シリアライゼーションとデシリアライゼーションがテキスト形式より高速
  • .proto スキーマ 12+ 言語に対して懈密な型付けとコード生成を提供
  • 下位互換性 によりクライアントを破さずに API を進化できる
  • gRPC はマイクロサービス通信の標準形式として Protobuf を使用
  • 理想的 高負荷システムやトラフィックの制限されたモバイルアプリに向けている

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください