[CodeIgniter] CodeIgniter + SQLite3の処理速度をベンチマーク

CodeIgniter+軽量なデータベースSQLiteの組み合わせで、どれくらいのパフォーマンスが出るのかを調べるために、ベンチマークをとってみました。

テスト環境

レコード: 1500レコード * 7カラム
サーバー:MacBook 12インチ Core m7
OS:Ubuntu Server 16.04 on Vagrant (1CPU 2GBメモリ)
PHP:PHP7 on Docker

処理能力はそこそこなサーバー(VPS 1GBプランくらい?)を想定して、仮想マシン上の設定は1CPU * 100%で設定しました。

MacBook 12インチの1CPU * 100%だと、CPU面ではさくらやConoHaなどのVPSの1コアプランよりも処理速度は劣っています(VPSは共有だとしてもXeonですので)。

逆に、Google Compute Engineのf1-microやラズパイクラスのサーバーでは、こんなに速度は出ないと思います。GCPのf1-microはUnixBenchで400弱ですので。

クエリを大量発行してテスト

まずは、どれくらい重いクエリに耐えられるかという基準を見たいので、単純にSELECTするだけのクエリをn回実行するテストをしてみました。

SQLiteのINSERTやUPDATEはデッドロック問題があるので、極力WEBサービスの本番では使わないほうが無難なので、テストしてません。もし、INSERTやUPDATEが必要なWEBサービスなら素直にMYSQLにしたほうが幸せになれます(たぶん)。

テストコード

set_time_limit(1200000);
$this->benchmark->mark('code_start');

$num = 1;

$i = 0;
while($i < $num){
    $this->DB1 = $this->load->database('default', TRUE, TRUE);
    $this->DB1->select();
    $this->DB1->from('table1');
    $this->DB1->where('status = 1');
    $data = $this->DB1->get();
    $result = $data->result_array();
    $i++;
}
$this->benchmark->mark('code_end');

echo $this->benchmark->elapsed_time('code_start', 'code_end');

なお、statusにはインデックスが張ってあります。

テスト結果

回数 1回目 2回目 3回目 4回目 5回目 6回目 7回目 8回目 9回目 10回目 合計時間(平均) 1回あたり(平均)
1 0.0151 0.0067 0.007 0.0091 0.0099 0.0108 0.0069 0.0072 0.0065 0.0081 0.00873 0.00873
10 0.0404 0.0572 0.0562 0.0488 0.0442 0.04 0.0415 0.0517 0.0493 0.0509 0.04802 0.004802
50 0.1792 0.2072 0.2125 0.1928 0.2104 0.1973 0.2157 0.2108 0.2365 0.1978 0.20602 0.0041204
100 0.3622 0.4093 0.3888 0.3629 0.4208 0.3641 0.4121 0.436 0.3823 0.3965 0.3935 0.003935
1000 3.5201 2.9524 3.063 3.1081 3.1574 3.2899 3.0568 3.4788 4.1001 3.1466 3.28732 0.00328732
10000 39.628 36.6413 36.5627 29.4827 34.1682 35.1158 34.1765 31.4448 42.4125 38.9293 35.85618 0.003585618

概ね、1クエリあたり0.003-4秒くらいと考えて良さそうですね。これくらいの速度が出てくれるなら、本番運用もできるかもしれません。

Apache Benchで負荷テスト

上記のテストは複数クエリを同時に発行した時のテストだったので、次はどれくらいのアクセスを捌けるのかを見るために、Apache Benchを使って負荷テストをしてみます。

1ページあたりに発行されるクエリは、記事一覧などなら50回くらいだと思うので、上記のプログラムを$num=50にセットしてテストします。

テストコード

テストコードは下記の通り。

ab -n 総リクエスト数 -c 人数 http://localhost/

※Dockerコンテナ内で実行します

Apache Benchのテストは、人数 x リクエスト数なので、人数を「10、50、100、250、500」の4パターン、リクエスト数を「それぞれ1PV、10PV、20PV」の3パターン、合計15パターンでテストしてみました。

テスト結果

テスト結果です。以下の表は右下に行くほど負荷が高いようになっています。

※数字は、1ページを表示するのに掛かった時間(sec)

人数 1 リクエスト 10 リクエスト 20 リクエスト
10 0.167722 0.168007 0.159569
50 0.169482 0.17029 0.194768
100 0.171719 0.206688 0.207012
250 0.203337 0.213868 0.234238
500 完了できず 完了できず 完了できず

おおよそ0.2秒以内、1秒あたり5リクエストというイメージですね。ちなみに、500人のパターンは、1人1リクエストでも処理が落ちてしまいました。

先ほどのテスト結果だと、50クエリの平均処理時間は0.2秒ほどだったので、ほぼ劣化しないか、むしろ速くなっています。多分同じクエリを発行しているからでしょう。

1秒で5リクエスト捌けると、

5 * 60秒 * 60分 * 24時間 * 30日 = 12,960,000PV

で、月間1300万PVほどを捌ける感じになります。実際にデータが増えたり、重い処理が入ったりして速度が1/4になったとしても、1リクエスト0.8秒ほどで捌ければ、月間300万PVくらいまで耐えられます。

これくらいのアクセスがあったら、少し高性能なサーバーを借りてもお釣りがくるはずなので(収入モデルがある場合はですが・・・)、アクセス負荷については当分気にしないで良さそうです。


こういうベンチマークはあくまで参考で、実際に開発を進めると「ベンチは速かったのに、動かしたら遅くない?」となりがちなので、あとはどのような効率の良いコードを書けるかによるかと思います。スロークエリが数個あるだけで、どんどん負荷がたまっていきますしね。

ただ、「おもちゃ程度」と言われるSQLite3ですが、単純に表示するだけのWEBサイトなどだったらかなりの負荷に耐えられることがわかったのは、個人的に収穫でした。

以上、CodeIgniter + SQLite3環境でのベンチマークテストでした。