マルチスレッドなら pwrite より mmap+msync のが速い (or Q4M のパフォーマンスの限界値に到達) という話
色々ユーザランドでのロックを使わない形に書き換えても、なかなか速くならなかったのが、pwrite をやめて mmap(PROT_WRITE) 経由での書き込みにしたら、20% 程度あった idle time が 0 になった。
ベンチマーク的にはこんな感じ。上が pwrite 経由。下が msync(MS_ASYNC) 経由の書き込み。どちらも読み込みは mmap。
$ USE_C_CLIENT=1 MESSAGES=400000 CONCURRENCY=40 DBI='dbi:mysql:test;mysql_socket=/tmp/mysql51.sock;user=root' t/05-multireader.t 1..4 ok 1 - check number of messages ok 2 - min value of received message ok 3 - max value of received message ok 4 - should have no rows in table Multireader benchmark result: Number of messages: 400000 Number of readers: 40 Elapsed: 13.326 seconds Throughput: 30016.656 mess./sec. $ USE_C_CLIENT=1 MESSAGES=400000 CONCURRENCY=40 DBI='dbi:mysql:test;mysql_socket=/tmp/mysql51.sock;user=root' t/05-multireader.t 1..4 ok 1 - check number of messages ok 2 - min value of received message ok 3 - max value of received message ok 4 - should have no rows in table Multireader benchmark result: Number of messages: 400000 Number of readers: 40 Elapsed: 10.744 seconds Throughput: 37229.444 mess./sec.
てか、pwrite は、API 的にはステートへの依存がなくなっているけど、(少なくとも手元の linux 環境 (x86_64; 2.6.18-53.1.14.el5; ext3) では) 内部での並走性はない (or 小さい) ってことですね。もっと早くここをいじるべきだったorz ... でもまあ他の lock も減らせたしいいことにしよう。単純な SELECT ... LIMIT 1 クエリの実行可能回数が 75k回/秒だったから、1行消費するために2回クエリを発行する Q4M の場合、パフォーマンスの限界値に到達したって感じw
ちなみに mmap+msync 経由の書き込みを使いたい場合は、Q4M の ./configure に --enable-mmap-writes=yes としてください。