PeerCastIM4Linuxをいじってみた
PeerCast には設定の為に HTML サーバーが実装されているが、そのパフォーマンスはさして感心するようなものでもない。Apache HTTP サーバーのベンチマークツールである ab で計測してみる1と、コンカレンシー 1〜4 の時のリクエスト毎秒は次の通り。
Requests per second: 94.13 [#/sec] (mean)
Requests per second: 93.90 [#/sec] (mean)
Requests per second: 94.16 [#/sec] (mean)
Requests per second: 94.72 [#/sec] (mean)
どうもなんらかの天井があるようだ。
ソースを見ると、ポートで接続待機するスレッドのエントリー関数の概要は次のようなものだった。
int Servent::serverProc(ThreadInfo *thread)
{
Servent *sv = (Servent*)thread->data;
// 待機状態にする。
sv->setStatus(S_LISTENING);
while ((thread->active) && (sv->sock->active()))
{
ClientSocket *cs = sv->sock->accept();
if (cs)
{
要求を処理するために新しいスレッドを起動する。
}
sys->sleep(10);
}
終了処理。
return 0;
}
accept はノンブロッキングであるので、接続要求があれば ClientSocket オブジェクトを返すが、なければ NULL を返す。要求のあるなしに関わらず 10 ms のスリープを行なうことで CPU 時間の浪費を防いでいる仕組みだ。
1秒 = 1000 msec なので、このやりかたではどうがんばっても1秒間に 100 回以上のリクエストに応えることはできない。およそ 94 リクエスト毎秒だったこともうなずける。
接続要求が大量に来た場合はシステムのキューに要求が溜まっているはずなので、accept が連続して成功する場合が多い。そこで、accept が成功した場合は sleep せずに次の accept をこころみるように変更してみる。
while ループを次のように変更した。
while ((thread->active) && (sv->sock->active()))
{
ClientSocket *cs = sv->sock->accept();
if (!cs) { sys->sleep(10); continue; }
要求を処理するために新しいスレッドを起動する。
}
コンカレンシー 1〜4 の時の RPS。
Requests per second: 94.01 [#/sec] (mean)
Requests per second: 182.73 [#/sec] (mean)
Requests per second: 279.56 [#/sec] (mean)
Requests per second: 363.40 [#/sec] (mean)
コンカレンシーを上げると線形に RPS も増加するようになった。
さらに、Unix 依存にはなるが2 poll を使っていつでも要求が来たらすぐさま accept できるように改造してみた。
#include <poll.h>
#include "../unix/usocket.h"
while ((thread->active) && (sv->sock->active()))
{
{
struct pollfd fd;
fd.fd = ((UClientSocket *) sv->sock)->sockNum;
fd.events = POLLIN;
fd.revents = 0;
int changed = poll(&fd, 1, 10); // 10 msec のタイムアウト。
if (changed == 0) {
// タイムアウトが起こった場合。
continue;
}
}
ClientSocket *cs = sv->sock->accept();
if (!cs)
continue; // 恐らく到達しない。
要求を処理するために新しいスレッドを起動する。
}
コンカレンシー 1〜4 の時の RPS。
Requests per second: 1743.66 [#/sec] (mean)
Requests per second: 2382.99 [#/sec] (mean)
Requests per second: 2009.52 [#/sec] (mean)
Requests per second: 1775.24 [#/sec] (mean)
なぜコンカレンシーに応じて RPS がこのように変化するのかはわからないが、ともあれ大幅に改善した。