見出し画像

Protocol Buffersを導入しログの送受信の実装を効率的に - データ基盤のログ収集改善

データ基盤チームです。

私たちのチームではログ収集のために、サーバサイドやフロントから日々データを送ってもらっています。

しかし、異なる言語や環境において、スキーマや型などに悩まされることが多くありました。特に、JSON形式ではスキーマの変更や互換性の確保が大きな課題になります。

そこで、ログ収集のデータ送付をProtocol Buffers(以下、protobuf)に移行することにしました。

これまでの課題

スキーマに従う手間

noteではもともとAPI仕様書を見ながらJSONを書いていたのですが、スキーマに従っていないデータを送れてしまう問題がありました。

極端なことを言えばJSONですらなくてもHTTP Message Bodyに入れて送信できてしまうのです。

{
  "data": {
    "params": {
      "id": 1,
      "user": {
        "uuid": "hogehoge"
      }
    }
  }
}

上記はJSONのサンプル仕様ですが、パラメータが増えたり、階層が増えたりすることで、さらに扱いが難しくなっていきます。

この状態だと、サーバサイドやフロントエンドからログを送ったあとに、受信側でエラーが発覚することになります。間違いに気づくのが遅くなってしまうのです。

しかし、上記のような問題も、protobufなら送信前にスキーマのチェックができるので、ミスを事前に防ぐことができます。

人が仕様を見ながら間違いのないようにログを送信するのは生産的ではないと考えています。ルールを定めてヒューマンエラーを防ぐ意味でも、protobufは大きな役割を持っています。

互換性を維持したアップデート

運用を続けていくとスキーマを変更したくなることがあります。しかし、安全にスキーマを更新するにはどうすべきか、というルールはチームで定まっていないこともよくあります。

そういった場合は、protobufに従うことにより、前方、後方互換性を維持して送受信それぞれを順次アップデートすることが可能になります。

Protocol Buffersの導入メリット

APIの自動生成による効率性の向上

protobufの導入により、自動生成されたバインディングを使うことで、各言語間の実装コストが大幅に削減されました。

// definitions/foo/user.proto
package foo;
message User {
  optional string first_name = 1;
  optional string last_name = 2;
}
module Foo
  class User < ::Protobuf::Message; end

  class User
    optional :string, :first_name, 1
    optional :string, :last_name, 2
  end
end

Rubyの場合は、上記のように.protoファイルに型定義を書くとAPIのコードが自動生成されます。また、新たにフィールドを追加する際も、スキーマを変更するとバインディングの再生成がされます。生成されたAPIのおかげで、スキーマに従う手間が大きく軽減されました。

また、Google公式からライブラリも提供されているため、各言語での自動生成も簡単に行うことができます。noteの場合は、以下の以下の言語のバインディングを生成して使用しています。

  • Go (ログ収集サーバー) 受信

  • TypeScript (frontend) 送信

  • Ruby (Railsアプリ) 送信

信頼性と互換性の確保

protobufはスキーマに基づいてデータを厳密に管理します。これにより、間違ったデータフォーマットの送信を防ぎ、前後の互換性を維持したままシステムのアップデートを行えます。

message User {
  optional string first_name = 1;
  optional string last_name = 2;
  optional int32 age = 3; // 新たに追加して、フィールド番号として3を与える
}

具体的なルールとして、一度使用したフィールド番号は再利用しないことが挙げられます。これにより、送信側と受信側のバージョンが異なっていても、データの互換性が保たれます。

また、上記のようにおもしろい使い方もあり、まだまだ活用の幅があるのだなと勉強になりました。

まとめ

protobufを活用することで、異なる言語からのデータ送信にも柔軟に対応できるようになりました。導入してみると、スキーマ定義も言語仕様も簡単に覚えることができるので、学習コストの低さも強みです。次はモバイルアプリにも対応していこうと思っています。

※ この記事はエンジニアのインタビュー内容をライターが再編しました

▼noteの技術記事がもっと読みたい方はこちら


みんなにも読んでほしいですか?

オススメした記事はフォロワーのタイムラインに表示されます!