現状報告はこちら
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を使ってミラーサーバを作ってみました。
ドメインが何故か空いていたので確保しました。
$ 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を取得しました。
私が生きているうちは面倒を見るつもりですので、自由に使っていただいて構いません。