packagist.orgのミラーサーバを立ててcomposer updateを18倍速くする #packagist

  • 79
    いいね
  • 4
    コメント
この記事は最終更新日から1年以上が経過しています。

現状報告はこちら

packagist.JPの現状について(2015年12月): Architect Note

以下原文

PHPのモダンな依存関係解決ツールであるcomposerですが、動作が遅いですよね。
私も常日頃から遅さを実感しており、何とかしたいと思っていました。

つい先日、GCを切るというハックによってだいぶ速くなりましたが、それでもpackagist.orgからのダウンロード部分は変わらず遅いままです。

Composer を倍速にした、たった 1 行のコード - Shin x blog

例えば、symfony/symfonyのインストールを考えてみます。

# ベンチマーク用の環境準備
$ mkdir composer-bench
$ cd composer-bench
$ composer require 'symfony/symfony:*'

# ベンチマークの公平性のためメタファイルのキャッシュだけ消す
$ rm -rf ~/.composer/cache/repo/https---packagist.org

この状態からcomposer updateしようとすると、これぐらい時間がかかります。(測定環境によってこの時間は大きく変わります。以下は私が試した結果です。)

$ composer update --dry-run --profile
[7.6MB/0.15s] Loading composer repositories with package information
[8.1MB/2.37s] Updating dependencies (including require-dev)
[111.3MB/309.87s] Nothing to install or update
Memory usage: 92.52MB (peak: 111.54MB), time: 309.9s

全く同じコマンドを直後に打つと、キャッシュが効いているのでもう少し早くはなるのですが、updateをうっかり打つと5分かかるとは、、ちょっと遅いですよね。。

composerが遅い理由

いくつか理由があります。

  • packagist.orgが日本から遠い
  • composerのアーキテクチャ的に、小さなjsonファイルを少しずつダウンロードするため、ネットワークの遅延がもろに影響する
  • composerがfile_get_contentsでjsonをダウンロードしていて、どうやらKeep-Aliveを使っていないし、並列ダウンロードもしていない

私は「composerがそもそもイケてないのだ」と思ったのですが、ソースコードもそれなりに巨大ですし、本体に手を入れるのは大変そうでした。

そこでミラーサーバ

コマンド一発で5分はあまりにアレなので、さくらVPSを使ってミラーサーバを作ってみました。

https://packagist.jp

ドメインが何故か空いていたので確保しました。

$ composer config -g repositories.packagist composer https://packagist.jp

こんな感じで、composerの設定に入れておくと、packagist.orgの代わりにこのミラーサーバを参照するようになります。設定を有効にした状態で先ほど5分もかかったcomposer updateを打ち込むと…

# ベンチマークの公平性のためメタファイルのキャッシュだけ消す
$ rm -rf ~/.composer/cache/repo/http---packagist.jp

$ composer update --dry-run --profile
[7.6MB/0.15s] Loading composer repositories with package information
[8.1MB/0.21s] Updating dependencies (including require-dev)
[111.2MB/16.73s] Nothing to install or update
Memory usage: 92.5MB (peak: 111.53MB), time: 16.75s

なんということでしょう。300秒が16秒で 18倍 ぐらい速くなってますね。これぐらいなら我慢できる範囲に収まるのではないでしょうか。

あくまでpackagist.orgとの通信がショートカットされるだけなので、ソースコード本体をgithubからダウンロードするところの速度はあまり変わらないかもしれません。あしからず。

ミラーサーバの中身

ミラーといっても完全なコピーではなく、composerコマンドに必要なファイルだけコピーしています。

composerはinstallやupdateコマンドを打つとpackagist.orgに問い合わせに行き、いくつかのJSONファイルをダウンロードします。このJSONファイルを前もって全部ダウンロードしておき、普通にApacheやNginxでJSONを配信すれば、ミラーサーバが出来上がります。 SolrとかMySQLとかは立てなくて大丈夫です!!

JSONファイルもクロールしやすくできていて、

https://packagist.org/packages.json
がまずあり、この中にパッケージ一覧が書かれたJSONファイルが4つ書かれています。

active, archive, latest, staleの4つのjsonファイルをダウンロードすると、それぞれの中に更にパッケージごとのJSONのパスが書かれているので、それらを上から順にダウンロードしていけばpackagist.orgの全データがコピーできるというわけです。

この辺のロジックと、あと高速にダウンロードするためのセッション管理、キャッシュ管理なども含めたスクリプトをgithubに置いているので、ミラーサーバを建てたい方は参考にしてみてください。
https://github.com/hirak/packagist-crawler

なお、packagist.jpの場合、packagist.orgとの同期は2分おきです。なので、最新のパッケージが反映されるまで最大2分のラグがある可能性があります。

必要なサーバスペック

JSONを全部ダウンロードすると500MBぐらいになります。意外と少ないですね。packagist.orgはあくまでパッケージのメタ情報だけを管理していて、ソースコード本体はgithubなどから配信しているので、これだけコンパクトなのです。

もちろんこれからパッケージが登録されるにしたがってデータ量も増えるはずですが、せいぜい数GBのディスクがあれば十分という感じですね。

あとは普通のWebサーバーとしてJSONを配布すればいいので、共用タイプのレンタルサーバーとかでも全然使えます。ただ、細かい静的ファイルを高速に配信できた方がいいので、チューニングを工夫すればもっと速くできるのかもしれません。

composer-proxy.jpとの比較

Composer Proxy JP
こちらは @ooharabucyou さんがメンテナンスされているpackagist.org専用のプロキシサーバです。

私も最初はcomposer-proxy.jpを使っていたのですが、あくまでプロキシなので、誰かがファイルをダウンロードしてくれないとキャッシュされません。キャッシュされていないファイルをダウンロードしようとすると、その人の体感速度はpackagist.orgを使っていた時と変わらないのです。

有名どころのパッケージだけを使っていればまだよいのですが、packagist.orgに個人的なパッケージをいくつか登録している身としては、そんな自分専用のパッケージを使ってくれる人は他におらず、しょっちゅうキャッシュヒットしない状態でした。

そういうわけで他にいい方法はないか考えてみて、自分用にミラーサーバを作るに至った感じです。

今後の展開

作れるかなーと思ったら案外簡単に作れちゃった、という感じなのですが、正直今後どうするかに困っています。

ダウンロードするJSONファイルはpackagistに登録されたパッケージ数だけあるので、今だと44,000ぐらいのファイルをダウンロードする必要があります。
日本のPHPerがこぞってミラーサーバを作ると、packagist.orgへのDOS攻撃になってしまいます。
(ちなみにこのミラーサーバを作るにあたって、packagistには何の許可もとっていません。怒られたらヤバいかもしれません。。)

中の人にメールして、2分おきぐらいだったらいいよ、という言質を取りました。大丈夫そうです。

ちゃんと運用していくなら、もっと権威のあるどなたかにお任せして、「日本のPHPerはみんな安心してこのミラーを使えばいいよ!」っていう風にしたいのですが、誰に相談すればいいですかねえ…

一応、ミラーサーバ自体は先述の https://github.com/hirak/packagist-crawler を使ってcronで定期的に同期すれば割とすぐ作れるようにはなっています。

追記(2015/01/03)

一応きちんとしたドメインを、ということでpackagist.jpを取得しました。
私が生きているうちは面倒を見るつもりですので、自由に使っていただいて構いません。

この投稿は PHP Advent Calendar 20146日目の記事です。