Home JavaScript Greasemonkey PHP

巨大なバイナリを扱えるバージョン管理システムを夢想してみる2009-01-15


某ゲーム会社に勤める友人が、巨大なバイナリを軽々と扱えるバージョン管理システムは無いものかというので、どんなシステムだったら実現可能か夢想してみました。

既存のバージョン管理システムの問題点

CVS/SVN などの中央管理型と Git を始めとする最近流行の分散管理型とがありますが、「巨大なバイナリ」を扱うという点に置いては、どちらも根本的な問題があります。
数 10 GB の単位のデータを扱う上では、今のネットワーク帯域が狭すぎるためです。

この点だけで言うと、マスタのフルサイズのコピーを持つ現在の分散型はきわめて不利と言わざるを得ません。
かといって、中央管理型が有利かというと、それはそれで中央サーバの帯域が圧迫されまくってしまう上、そもそも帯域が狭すぎて DL に時間がかかってしまうという問題は解決できていません。

そんなわけで、巨大なバイナリを扱う上では、そのコピーに大きなコストがかかるという事を前提に、あるべきシステムを考えてみます。

中央型か分散型か

既存のシステムでは分散型の方が不利というのは確実ですが、いざ実際のシステムを考えた場合には、やはり分散型を基準にした方が良いと思われます。
コミットの度に中央サーバにアクセスするのは、ネットワークの負荷が高すぎます。

そこで、分散型を採用しつつ、リポジトリのマスタのコピーはローカルに持たないというアプローチを採用したいと思います。

ではどこにマスタを持つのか?

答えは P2P の中にありました。

Winny ネットワークの事を考えてみましょう。
Winny ネットワーク自体を超巨大な 1 つの仮想的なストレージと考えた場合に、その全てのファイルを持ったサーバは 1 台として無く、確実にファイルが存在するのは、始めにオリジナルを流したその PC だけです。

もちろん、ダウンロードした PC にはオリジナルのコピーが存在する事になりますが、どこの誰が DL するかは分からないですし、断片だけを持った PC が何台あるかも分からないという意味で、"確実に" オリジナルが存在するのは放流元だけと考えて下さい。

この仮想的なストレージを、P2P 型リポジトリとしてバージョン管理システムに活かす事は出来ないでしょうか?

P2P 型リポジトリとは

仮に Winny ネットワークをリポジトリのように使用する場合、自由度が高すぎて、開発作業を行うのに十分な管理が出来ません。
そこで、P2P 型リポジトリには、中央サーバが必要だと考えられます。
ただ、SVN 等とは違って、中央サーバはリポジトリを持つのではなく、いわば仮想リポジトリのファイルツリーを管理するサーバです。

ユーザは中央サーバを参照する事によって、仮想リポジトリの全容を把握する事は出来ますが、それを元にファイルを取得する場合、ファイルの取得先はあくまで P2P でオリジナルを持った PC からダウンロードされます。

ファイルのコミットは、一応、中央サーバに対して行います。
このとき、中央サーバは何というファイルがどの PC でコミットされたか、そのバージョンがいくつか、を記録しますが、ファイル自体は個々の PC にあるままの状態になります。
本当にそのファイルが他の人から必要とされるまでは、帯域を消費しないという事です。

これが P2P 型のポイントになります。

P2P 型利用イメージ

  1. ファイルの新規コミット
    A さんがローカル PC で新しくリポジトリに追加するファイルを作成したら、中央サーバに対してコミットを宣言します。
    このとき、仮想リポジトリのファイルツリーでどのパスにコミットするかを指定しますが、中央サーバが管理するのはオリジナルが存在する場所と、バージョン情報と、仮想リポジトリのパスだけです。
  2. ファイルの取得
    B さんがそのファイルを更新しようとする場合、まず中央サーバに問い合わせて、オリジナルの存在する場所を取得します。
    その結果、A さんの PC にファイルが存在する事が分かったら、あとは、A さんと B さんの間で P2P 通信を行い、ファイルをコピーします。
  3. ファイルの更新
    B さんが、ファイルの更新を終えたら、中央サーバにコミットします。
    この時点で、ファイルのバージョンと、オリジナルが存在する場所が更新されます。もちろん、新規コミット時と同様、ファイル自体のコピーは行われません。
  4. コミットの通知
    B さんがファイルをコミットした事を、中央サーバは A さんに対してプッシュ型で通知します。このタイミングで A さんは、新しいバージョンのファイルをローカルに取り込むか、取り込まないかを選択します(クライアントアプリでは、自動取り込み or 自動拒否オプションなんかを実装して欲しいですね)。
    また、A さん以外にも、過去に同じファイルを編集した人がいる場合、全員のところに通知がいくようにします。近い将来、再度ファイルを更新する予定がある人は、このタイミングで取り込んでおいた方が良いです。
コミットの通知については、少し説明を加えます。

複数の人が関わるバージョン管理システムではどうしても「競合」が発生します。ファイルを取り込んでコミットするまでの間に、自分以外の人が同じファイルを編集しているという状態です。
従来のバージョン管理システムでは、競合の発生が明らかになるのはコミット (もしくは明示的な更新) を行うタイミングなので、そのタイミングでリポジトリから最新を取りなおして内容をマージするという事が行われています。

しかし、巨大バイナリのダウンロードにはどうしても一定の時間がかかってしまうので、いざファイルをコミットしようとした時に競合が明らかになるようだと、ダウンロードからやり直しになり非効率です。
さらに対象がバイナリファイルとなると、マージも簡単ではありません。

コミット通知は巨大バイナリの競合をなるべく回避するための仕組みになります。
競合を完全に防ぐ事は出来ませんが、コミット通知+人と人とのコミュニケーションがあれば、大概のケースでは問題なく運用できるのではないでしょうか。

以上が、P2P 型バージョン管理システムのあらましになります。

P2P 型をさらに改良する

さらに追加で、以下のような機能を実装すると幸せになれそうな気がします。
  • 断片キャッシュ機能
    まさに Winny と同様の発想です。ファイルのダウンロードの際には途中の経路に断片をキャッシュさせる事で、他の人が同じファイルを必要とした時にネットワーク的に最も近い端末からダウンロードする事が出来るようになります。
    狭い範囲での利用であれば、専用のキャッシュサーバを持つような構成にすることで、よりパフォーマンスを稼げるでしょう。また、複数拠点の開発ならば、キャッシュサーバは必要不可欠と考えられます。
  • 差分ダウンロード機能
    バイナリでこれが実現可能なのかは分からないのですが、可能なのであれば更新時は差分のみをダウンロードしてマージする機能が欲しいです。
    非圧縮の画像とか、MotionJPG などファイルタイプに特化すれば一部は実現可能な気もします。
  • ファイル圧縮機能
    現状のマシンパワーで言えば、圧縮・展開のコストの方がネットワーク帯域よりも安いので、ファイルコピーを行う際に自動的に圧縮を行う機能は、プロトコルレベルで実装してしまって良いかと思います。
  • バックアップ機能
    オリジナルファイルが分散してしまう事でバックアップに不安が残りますが、それは、中央サーバが仮想リポジトリをミラーリングすることで解決を試みます。
    PC のアイドル時やネットワークが比較的すいている時などに、中央サーバから各クライアントのオリジナルファイルを吸い上げるようにしておきます。
    「コミットから 24 時間以上経ったら、PC 負荷が高くても吸い上げを開始する」オプションなんかも欲しいですね。
    このミラーリングされたリポジトリは、通常時は一切使用しませんが、万一データが失われた際にバックアップとして使用する事が出来ます。

利用シーン

P2P 型バージョン管理システムは、かなり限定された環境でのみ大きな効果を発揮します。通常のソースコードの管理であれば、SVN や Git の方が確実に管理しやすいです。
そもそも、ソースコードのようにコンパイル時に全てのセットが必要なものについては、P2P 型のアプローチは全く無意味です。
まさに巨大バイナリ専用と考えた方がいいかもしれません。

開発を行っている部署単位で、全員まとめて一気に導入というのが一番あり得る利用シーンですね。1TB のストレージと 1 Gbps のネットワークは全員の PC に標準装備という様な環境でのみ、活用可能なシステムだと考えられます。

あとは

誰か作んないですかね~。