速いアプリケーションの作り方

Phalcon Adventカレンダー18日目として書いています。

一台のアプリケーションサーバーで10リクエスト/秒で十分というサービスであれば、どんなプラットフォームを選んでも問題ありません。一台のサーバーが10リクエスト/秒しか処理できなくても、ページがキャッシュできるならリバースプロキシで簡単に数千リクエスト/秒以上でサービスできます。このようなサービスであればPhalconのようなフレーワムワークを使わなくても大丈夫です。

しかし、メッセージング系などリアルタイム性の高いサービス、つまりHTTPキャッシュがあまり有効に利用できないシステムでは速度が非常に重要です。

“速いアプリケーションの作り方” の続きを読む

Phalcon PHPとSails Node.jsのベンチマーク

以前にフレームワーク対決:Node.js+SailsとPHP+PhalconのベンチマークとしてPhalconとSailsのベンチマークを行ったのですが、Apacheを利用した場合のPhalconの性能が全く違うので取り敢えずブログに書きます。

このエントリはPhalcon Adventカレンダー17日目として書きました。少し前に設定がおかしいことに気づいて非公開にしていた物を修正しています。

“Phalcon PHPとSails Node.jsのベンチマーク” の続きを読む

PHP 5.4のビルトインWebサーバの性能

PHP 5.4からCLIのphpコマンドにビルトインWebサーバ機能が追加されています。

ツイッターでWebrick(RubyのビルトインというかRuby製のWebサーバ)+素のRailsページはjRubyで44reqs/sec、cRubyで98reqs/secでした、とのツイートを見かけて、PHPのビルトインWebサーバはどの程度かな?と思って手元のマシンで実行してみました。 “PHP 5.4のビルトインWebサーバの性能” の続きを読む

簡単なベンチマーク

最近のPostgreSQL, MySQL, SQLiteのパフォーマンスはどうかな?と言うことで非常に簡単なベンチマークをしてみました。

デフォルト状態のデータベースに郵便番号データ(12万件とちょっと)をINSERTしてみました。フラグを除く全てのフィールドをテキスト型として定義し、全てのフィールドを挿入しました。旧番号と現行番号にインデックスを付けています。スクリプトはPHPで記述し、DBが動作しているPC上からPHP 5.2.4で実行しました。1レコードが分割されている場合などは無視して挿入しているので12万2000レコードになりました。

PC

CPU: PentiumD 2.8GHz
Memory: 3GB
HDD: PATA

DBMS

MySQL: 5.0.45
PostgreSQL: 8.2.4
SQLite: 3.4.0 (PDO)

実行結果(12万行INSERTの実行時間)

InnoDb: 130.70663690567
MyISAM: 131.24672317505
Postgres: 159.47350597382
SQLite: 676.43534302711

MySQLもPostgreSQLもチューニングは一切無しで実行しています。

非同期クエリを利用するとPostgreSQLもInnoDb, MyISAMと同じくらいの速度になりました。

どのDBもペンチマーク中はディスク待ちの状態でCPU時間はあまり使っていませんでした。

MySQLとPostgresは概ね予想通りの結果でしたが、SQLiteが異常に遅いのでPDOを使わないで計測してみましたがあまり変わりませんでした。トランザクションかな?と思いBEGIN, COMMITを付けてみましたが変わりませんでした。

INSERTしたレコードをランダムにSELECTしてみました。番号はmt_rand関数で生成したのでほとんどがINDEXにヒットしないので、インデックスを利用した検索の最悪のケースのテストになります。単純にテーブルから検索をするだけです。永続的接続を利用しています。

Webサーバ:Apache 2.2.6
クライアント: ab -n 10000 -c 10 (別PCから実行。Athlon64 3500+/3GBメモリ)

パフォーマンス:リクエスト/秒

Postgres: 947.58
SQLite: 1096.00
MySQL(MyISAM): 1190.35
MySQL(InnoDb): 1245.85

概ね予想通りの結果ですが、SQLiteが思っていたより遅いです。PostgreSQLは接続のネゴシエーション処理が重いので非永続的接続を利用するとかなりパフォーマンスが落ちます。システム全体でDBへの接続数を上手に制御できていない場合はpgpoolを利用するとパフォーマンス(システム全体のスループット)が改善することがこの事からも分かります。

「Postgresでこんな数字でないよ」という方、pg_pconnectで試してみましょう。コネクションプーリングが無いと話になりません。

PostgreSQL 8.1のパフォーマンス

PostgreSQLのパフォーマンスはpostgresql.confに大きく影響されるので、速くなったかどうか判りづらい場合も多いです。しかし、8.1では確実に速くなっているようです。現在8.1はbeta1ですが少しだけ比較してみました。

詳しくはWikiのページを見ていただくとして以下の様にpgbenchで計測すると

./pgbench -v -h 192.168.100.204 -U yohgaki -c 20 -t 200

PostgreSQL 8.0.3

tps = 4683.835265 (excluding connections establishing) (Select only)
tps = 1032.798585 (excluding connections establishing) (Update 省略)
tps = 423.926137 (excluding connections establishing)

PostgreSQL 8.1beta1

tps = 5985.801678 (excluding connections establishing) (Select only)
tps = 1428.605103 (excluding connections establishing)(Update省略)
tps = 533.005286 (excluding connections establishing)

という感じの結果になりました。
postgresql.confの設定は多少チューニングした物を使っています。postgresql.confもWikiのページに添付してあります。

pthread版pgbenchの拡張

実はpthread版pgbenchの作成には別の目的もあります。オリジナル版pgbenchのコードを見ると分かるのですが、非同期クエリを使用しているので送信するクエリのカスタマイズが面倒です。pthread版pgbenchの別の目的、と言うより本来の目的、はpostmasterが書き出したログから自動的にクエリを収集し、再生するベンチマークを簡単に行いたいので作る、と言う事にあります。

今の所こんな感じで実装するつもりです。

postgresql.confのログ設定が

log_line_prefix = ‘%r’
log_statement = true

で出力されたログから自動的に各クライアントのクエリを出力し設定されたスレッド数(クライアント数)でベンチマーク出来るようにする予定です。

今のコードだとログの読み取りとクエリ保存を行えるようにして、各スレッドがクエリを実行するように変更すれば良いだけです。簡単なのでそのうち変更します。

pgbenchのpthread版

(やはりバグを発見したので修正)

JPUG広報Blogに「pgbenchのpthread版が欲しい」と書いていましたが、先週末にPHP関西のセミナー講師を引き受けていたのでその移動時間中にテキトーに作ってみました。テキトーに作ったので勘違いしてバグを入れていました。今度はたぶん正しい結果になっていると思います。

サーバ環境
Athlon64 3200/3GB Memory/SATA2 HDD/Momonga Linux x86_64
PostgreSQL 8.0.3(64bit)(全てのSQL文をホスト/ポート付きで記録。他はほぼデフォルト。)

クライアント環境
AthlonXP 2500+/2GB Memory

pthread版pgbench

[yohgaki@dev pgbench]$ time ./pgbench -v -h 192.168.100.204 -U yohgaki -c 10 -t 100
starting vacuum…end.
starting full vacuum…end.
Warming up 15 seconds…
Start benchmarking…
End benchmarking….. (4.96586 seconds)
transaction type: TPC-B (sort of)
scaling factor: 10
number of clients: 10
number of transactions per client: 100
total number of transactions processed: 1000
tps = 235.404176 (excluding connections establishing)

real 0m25.739s
user 0m0.214s
sys 0m0.313s
[yohgaki@dev pgbench]$

こんな感じです。

何だか遅くなってしまたのでコードをもう少し効率化してみました。
今度はオリジナル版よりは速くなりました。

pthread版pgbench

[yohgaki@dev pgbench]$ time ./pgbench -v -h 192.168.100.204 -U yohgaki -c 50 -t 10
starting vacuum…end.
starting full vacuum…end.
Warming up 0 seconds…
Start benchmarking…
End benchmarking….. (1.16363 seconds)
transaction type: TPC-B (sort of)
scaling factor: 1
number of clients: 50
number of transactions per client: 10
total number of transactions processed: 500
tps = 429.689481 (excluding connections establishing)

real 0m2.655s
user 0m0.047s
sys 0m0.088s

オリジナル版

[yohgaki@dev pgbench]$ time pgbench -v -h 192.168.100.204 -U yohgaki -c 50 -t 10
starting vacuum…end.
starting full vacuum…end.
transaction type: TPC-B (sort of)
scaling factor: 1
number of clients: 50
number of transactions per client: 10
number of transactions actually processed: 500/500
tps = 337.674248 (including connections establishing)
tps = 379.093451 (excluding connections establishing)

real 0m1.615s
user 0m0.043s
sys 0m0.210s

と、多少スレッド版の方が速いです。今度は繰り返し実行してみてもスレッド版の方が速い傾向は変わりませんでした(汗

ベンチマークを開始する前にウォーミングアップの時間を設定したかった事、クエリ実行間隔をランダムに設定したかった事もpthread版が欲しかった他の理由でした。そこで

-w ウォームアップ時間(秒)
-r ランダム遅延(マイクロ秒)

も設定できるようにしました。よくあることですがサーバに負荷をかけた直後は良い性能がでるためウォームアップ時間は設定できた方が便利です。

ウォームアップ時間を5秒に設定した場合

[yohgaki@dev pgbench]$ time ./pgbench -v -h 192.168.100.204 -U yohgaki -c 50 -t 10 -w 5
starting vacuum…end.
starting full vacuum…end.
Warming up 5 seconds…
Start benchmarking…
End benchmarking….. (1.48874 seconds)
transaction type: TPC-B (sort of)
scaling factor: 1
number of clients: 50
number of transactions per client: 10
total number of transactions processed: 500
tps = 335.854481 (excluding connections establishing)

real 0m6.671s
user 0m0.124s
sys 0m0.260s

とこの様な感じです。オリジナル版にウォームアップ時間オプションを追加して欲しいな、と書いておいたら石井さんが追加してくれるはず 🙂

ソースは
http://www.ohgaki.net/wiki/index.php?PostgreSQL%2Fppgbench
からダウンロードできます。変更するかもしれないので日付を入れておきました。日付が入っていないソースは古いソースです。もし古いソースをお持ちの場合、新しいソースを使ってください。古い物にはバグがあります。

SATA IIのベンチマーク

メモ。ITMediaのSATA IIのベンチマーク。

SATA IIのNCD(Native Command Queuing)の効果は期待していたよりは効果が低いですがBarracuda 7200.8 SATA NCQ速いですね。

順次読込みは130Mバイト/秒に達している。これは、コントローラがPCI-Expressに接続されていないと性能をフルに発揮できないことを示している。

これって私のSATA IのLinux BOXでhdparmした時の倍くらいの速度です。130MB/秒だと1Gbpsを超える速度ですが、133GBプラッタのHDDはそんなに速い?! と思いSeagateのサイトに行きHDDのデータシートを見てみると

Sustained Transfer Rate (Mbytes/Sec) 65

と記載されていました。

「OSSの性能・信頼性評価/障害解析ツール開発」の成果を公開

OSCでもこの手の発表が聞けると思えますが、聞けなくて残念。

開発基盤ワーキンググループに関するドキュメントで、一般公開可能なドキュメントをダウンロードすることができます。
他のワーキンググループや日本OSS推進フォーラム全体に関するドキュメントは、左のメニューから選択してダウンロードしてください。
ダウンロードは下記ドキュメントのタイトルをクリックしてください。

「OSSの性能・信頼性評価/障害解析ツール開発」の成果を公開しました

http://www.ipa.go.jp/software/open/forum/DevInfraWG.html

HDDのパフォーマンス

折角久しぶりにLinuxマシンのSATAドライブが動作したのでhdparmで速度を測定してみました。

[root@sena root]# hdparm -tT /dev/hdb

/dev/hdb:
Timing buffer-cache reads: 3400 MB in 2.00 seconds = 1700.85 MB/sec
Timing buffered disk reads: 122 MB in 3.04 seconds = 40.11 MB/sec
[root@sena root]# hdparm -tT /dev/sda

/dev/sda:
Timing buffer-cache reads: 3408 MB in 2.00 seconds = 1704.85 MB/sec
Timing buffered disk reads: 160 MB in 3.02 seconds = 53.03 MB/sec

普通の速度は出ているようです。

そういえば「高速ネットワーク通信実験に成功。DVD一枚分のデータが数秒で送信可能」という見出しの記事を見掛けますが、数秒で送るにはメモリから送信しないとダメですね。仮に私のPCではDVD一枚分を数秒で送信するとして、十分なメモリがあってもPC3200 Dual Channelでは厳しそうな感じですけど… 実用化するときにはMRAMが湯水のように使える時代になっているのでしょうね。