予約フィールドとフィールド番号管理

reserved宣言によるフィールド番号と名前の管理。フィールド番号の再利用が危険な理由、フィールドの安全な廃止方法、スキーマ進化のベストプラクティスを学びます。

Enums & Oneof

詳細な説明

Reservedフィールドによる安全なスキーマ進化

protobufメッセージからフィールドを削除する際は、そのフィールド番号と名前の再利用を防ぐ必要があります。異なる型でフィールド番号を再利用すると、古いコードと新しいコードが相互作用する際にデータ破損を引き起こします。

syntax = "proto3";

message UserProfile {
  // 現在のフィールド
  int64 id = 1;
  string username = 2;
  string email = 5;
  string avatar_url = 8;
  bool is_verified = 9;

  // フィールド3, 4, 6, 7は過去のバージョンで削除
  reserved 3, 4, 6, 7;
  reserved "first_name", "last_name", "phone", "address";

  // 範囲指定もサポート
  // reserved 100 to 199;
}

Reservedが重要な理由

reservedなしのシナリオを考えてみましょう:

  1. バージョン1: string phone = 3; — フィールド3は電話番号を含む文字列
  2. バージョン2: phoneフィールド削除、開発者がint32 age = 3;を追加 — フィールド3は整数に
  3. バージョン1でシリアライズされたメッセージをバージョン2が読み取る:電話番号の文字列が整数として解釈され、破損やクラッシュを引き起こす

reserved 3;を使用すると、コンパイラがフィールド番号3の再利用を許可しなくなり、コンパイル時にこのエラーを検出します。

予約名 vs 予約番号

  • 予約番号はワイヤーレベルの破損を防止(最も重要)
  • 予約名はJSONフォーマットの衝突とソースコードの混乱を防止
  • ベストプラクティス: 削除されたすべてのフィールドの番号と名前の両方を予約

フィールド番号範囲

フィールド番号は有限のリソースです:

範囲 目的
1-15 1バイトタグエンコーディング — 頻繁にアクセスするフィールドに使用
16-2047 2バイトタグエンコーディング — 標準フィールド
2048-536,870,911 3バイト以上 — まれに使用
19000-19999 protobuf実装により予約 — 使用不可

廃止パターン

フィールドを即座に削除する代わりに、まず非推奨としてマークします:

message Config {
  string name = 1;
  string old_setting = 2 [deprecated = true];
  string new_setting = 3;
}

ユースケース

複数のサービスバージョンが共存し、ローリングデプロイメント中のデータ破損を避けるために後方/前方互換性が不可欠な大規模組織での本番protobufスキーマの安全な進化。

試してみる — Protobuf Definition Parser

フルツールを開く