シリアライゼーションとは?データをバイトに変換する仕組みを解説
シリアライゼーションとは、メモリ上のデータ構造を、ディスクに保存したりネットワーク経由で送信したりできるバイトストリームへ変換するプロセスです。
プログラムはデータをメモリ上のオブジェクトとして保持しますが、ディスクやネットワークはバイトしか扱えません。シリアライゼーションは、生きたオブジェクトを、保存または送信できるフラットなバイト列へ変換する翻訳作業です。CIのjobがJSONを書き出したり、buildをcacheしたり、payloadをネットワーク越しに送るたびに、その裏でシリアライゼーションが行われています。
シリアライゼーションとは何か
シリアライゼーションは、構造化された値 - オブジェクト、リスト、ネストしたレコード - を、後で再構築できるだけの情報を保持した線形のバイトストリームへと平坦化します。逆の操作であるデシリアライゼーションは、それらのバイトからメモリ上の構造を再構築します。この二つは常に対になっています。
テキストフォーマットとバイナリフォーマット
シリアライゼーションのフォーマットはテキストとバイナリに分かれます。JSONやYAMLのようなテキストフォーマットは人間が読めてデバッグしやすい一方、サイズが大きく処理も遅めです。Protocol BuffersやMessagePackのようなバイナリフォーマットはコンパクトで高速ですが不透明です。この選択は、可読性とサイズ・速度のトレードオフになります。
スキーマと互換性
二つのシステムがシリアライズされたデータをやり取りするとき、両者はその形について合意している必要があります。スキーマベースのフォーマットはその契約を明確に固定し、フォーマットが安全に進化できるようにします - 古いリーダーを壊さずにフィールドを追加する、といった形で。この前方・後方互換性は、サービスが独立してdeployされる場合に不可欠です。
CIにおけるシリアライゼーション
CIは絶えずシリアライズを行います。ツールはJSONやXMLのレポートを書き出し、cacheは後で復元するために依存関係ツリーをシリアライズし、jobの出力は下流のjobに読まれるためシリアライズされます。その多くは目に見えませんが、cacheやレポートのロードが失敗するときは、シリアライゼーションやバージョンの不整合が原因であることがよくあります。
# A job serializes data another job deserializes
jobs:
build:
outputs:
meta: ${{ steps.gen.outputs.meta }}
steps:
- id: gen
run: echo "meta=$(jq -c . build.json)" >> $GITHUB_OUTPUTLatchkeyについて
Latchkeyの依存関係cacheは、実行間でパッケージをシリアライズして復元します。cacheのフォーマットが標準的なため、あるLatchkeyの実行で生成されたcacheは次の実行でも問題なくデシリアライズされ、ウォームbuildを高速に保ちます。
重要なポイント
- シリアライゼーションはメモリ上のデータを、保存や転送のためのバイトストリームへと平坦化する。
- テキストフォーマットは可読性が高いがサイズが大きく、バイナリフォーマットはコンパクトだが不透明。
- CIはレポート、cache、jobの出力を絶えずシリアライズする - 不整合はロード失敗として現れる。