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

## 現状報告はこちら
[packagist.JPの現状について（2015年12月）: Architect Note](http://blog.tojiru.net/article/431831556.html)

## 以下原文

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

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

[Composer を倍速にした、たった 1 行のコード - Shin x blog](http://www.1x1.jp/blog/2014/12/composer-became-twice-faster.html)

例えば、[symfony/symfony](https://packagist.org/packages/symfony/symfony)のインストールを考えてみます。

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

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

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

```bash
$ 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

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

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

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

```bash
# ベンチマークの公平性のためメタファイルのキャッシュだけ消す
$ 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](http://composer-proxy.jp/)
こちらは @ooharabucyou さんがメンテナンスされているpackagist.org専用のプロキシサーバです。

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

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

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


## 今後の展開

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

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

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

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

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

## 追記(2015/01/03)

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