BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース Facebook、MercurialをGitよりも速くする

Facebook、MercurialをGitよりも速くする

原文(投稿日:2014/01/09)へのリンク

FacebookがエンジニアリングBlogにScaling Mercurial at Facebookという記事をポストした。この記事は、自分たちのリポジトリに合わせてMercurialをどのように変更したのか、説明している。

Facebookはすべてのコードを単一のリポジトリに格納している。今より2年前、そのリポジトリはSubversionをベースにしていた。彼らは独立したプロジェクトを個別のリポジトリにする(そしてバイナリリポジトリを使って共有する)代わりに、コードベース全体を単一の巨大なソースリポジトリとして管理していた。

Facebookにとって不運なことに、GitもMercurialも、単一の巨大なリポジトリをサポートするようには設計されていなかった。分散型バージョン管理システムの目的はあらゆる履歴を格納することだが、会社の全プロジェクトを単一のリポジトリに格納すると、履歴を含むリポジトリのサイズは極めて巨大なものになる。これに対して、CVSやSubversionなどの中央集権型のバージョン管理システムでは、複数のプロジェクトを単一のリポジトリで扱うことができる。なぜなら、クライアントは最新バージョンだけ、あるいはリポジトリの一部だけをチェックアウトできるためだ。

Facebookチームは自分たちのニーズをサポートするようGitを変更できないか調査したが、彼らの出した結論は、自分たちの要求をサポートするには、Mercurialの方がフック可能な適切なAPIを備えていて都合がよいというものだった(Gitがツールによって解釈されるオブジェクト構造をきちんと定義しているのに対し、Mercurialはコードベースによって使われる低レイヤのAPIを用意している)。彼らは多数の変更を上流のMercurialプロジェクトにコントリビュートしている。これには新しいグラフアルゴリズムCによるコードの書き直しも含まれている。

彼らは2つの変更をすることで、FacebookのリポジトリサイズでもMercurialが使えるようにした。ひとつはコンテンツの変更に対して特定のファイルだけをチェックするようファイルの状態更新を変更したこと(OSのファイル変更リストにフックすることによって)、そして、もうひとつは完全な履歴状態を必要としない軽いあるいはshallow cloneをするようチェックアウトを変更したことだ。

通常、分散型バージョン管理システムでは、タイムスタンプではなくデータの内容に基づいてハッシュを生成する。そのため多くの場合、リポジトリに変更があるかどうかを計算するためには、すべてのファイルをスキャンし、それぞれのハッシュを計算し、ファイルの内容に違いがないか判断する必要があった。そこで彼らは、チェックすべきファイルを最終スキャン以降に変更があったとOSが報告するファイルに限定するようにした。こうすることで、状態の更新スピードは、現在のワークスペースにある全ファイル数ではなく、タイムスタンプが変わったファイル数に比例するようになる。Gitではこうしたファイル固有の情報を得るのにlstatを実行することで高速化しようとしているが、変更されたかどうかを判断するには、依然としてレポジトリにある全ファイルをスキャンする必要がある。これに対し、彼らはこうした情報の提供をOSに任せることで、OSによって報告されたファイルだけをスキャンするよう最適化した。

Facebookが解決しようとしたもうひとつの問題は、pullやclone操作に必要なデータ量を最小限にすることだった。すべてのプロジェクトを同一リポジトリに格納すると、リポジトリのサイズは履歴全体に比例することになり、最終的にスケーリングの問題を引き起こしてしまう。リポジトリを効率よく分割することはできず、彼らはファイルの最新バージョンだけをコミットログとともにダウンロードするという解決策をとった。

これによって開発者は、現在のファイルをすばやく取得できるようになり(SubversionとCVSが実行するのとほとんど同じように)、その時点に至るコミット集合のログをイテレートすることができる。ただし、リポジトリの古いリビジョン(あるいは、ファイルの古いリビジョン)が必要になっても、ローカルのcloneはそうした情報を持っていない(Gitは'shallow clone'による制限オプションを提供しており、リポジトリから単一のリビジョンを取得できるがコミット履歴は含まれていない。)

彼らはMercurial APIを拡張して、コミットに欠けているオブジェクトが必要になると、「フォールト」が発生してリモートサーバからコンテンツをダウンロードできるようにした。これにより、本当に必要になるまではダウンロードする必要がなくなる。もちろん、これは中央サーバがダウンしたり利用できなくなった場合、開発者は古いバージョンのコードをチェックアウトできなくなることを意味する。しかし、コミットログは利用可能でき、新しいコミットをしてサーバにプッシュすることはできる。(これに対して、gitのshallow cloneは同じコンテンツを持っているが、リードオンリーでのみ使えることを意味する異なるコミットを持つ。)

これらの改善はmemcachedレイヤと合わせて、pull/cloneと作業ディレクトリの状態計算をGitと比べて5倍効率改善し、FacebookのMercurial利用を加速させている。これらはremotefileloghgwatchmanにあるFacebookのmercurialリポジトリ経由で利用可能だ。この設定とアプローチはすべてのMercurialユーザに適しているわけではないが、Gitによる独占が進むオープンソースの世界で、分散型バージョン管理システムをさらに後押しすることになるだろう。

この記事に星をつける

おすすめ度
スタイル

BT