2014年5月26日月曜日

mod_ratelimit: クライアント向けの帯域制限

レート制御モジュールは出力フィルタで実装されている。
環境変数 rate-limitsで接続ごとの送信データレートを指定できる。
単位はKB/秒。

<Location /downloads>
  SetOutputFilter RATE_LIMIT
  SetEnv rate-limit 400
</Location>
参考: http://httpd.apache.org/docs/2.4/mod/mod_ratelimit.html

指定するレートの値が環境変数なので、条件によって変更が効くという自由度があるが、他方、処理内でsleepしてタイミングをとっているのが event MPMとの組み合わせではいけていない気がする。
mod_dialup()との比較はどうだろうか。

この処理ではレート制御は個々のレスポンスデータの送信に適用される。サーバが処理する送信全体の帯域制御などの用途ではない。少数の大きなファイルのダウンロードなどで通信帯域が枯渇するといった問題を緩和するために利用されるのだろうか?(最近のTCPのレート制御事情がどうなっているのかは知らないが、既に帯域が消費されている状態からでは、後続の接続はなかなかスピードアップは計れない気がする。どうだろう)。

出力フィルタ処理を見ていく。
出力フィルタの概要 を前提にする。

2014年5月19日月曜日

出力フィルタの概要

apache 2.4で追加されている ratelimitモジュールは出力フィルタだ。
これを調べてメモを作っていたが、出力フィルタについての説明がないことに気がついた。

私もぼんやりとは分かっているつもりだが、きちんと説明できる自信もないので、出力フィルタについて調べて書いてみる。
まず大きな枠組みの説明をして、必要に応じて、細かい説明を今後別記事で起こしていこうと思う(最終的には何かまとまった記事になればと思う)。

フィルタについてはApacheプロジェクトの以下のページに概要が書かれている

Filters
http://httpd.apache.org/docs/2.2/en/filter.html

開発者向けのドキュメントにも詳しい説明が見られる。

How filters work in Apache 2.0
http://httpd.apache.org/docs/2.4/en/developer/filters.html

Guide to writing output filters
http://httpd.apache.org/docs/2.4/en/developer/output-filters.html


フィルタには2種類ある。入力フィルタと出力フィルタだ。
入力フィルタは、外部からネットワークを通って受け取ったデータを、メインの処理(Content Generator)に渡す前に加工する。
出力フィルタは、メインの処理(Content Generator)が送信するデータを、実際にネットワークに送出する前に加工する。
これらのフィルタは、設定によって、自由に追加削除できるものもある。

まず、出力フィルタを説明する。
入力フィルタもそのうちにまとめる。

フィルタとともにApacheの重要なコンポーネントにハンドラがある。
これもそのうちまとめたい。

その上でモジュールの説明を書けば、よいのではないか。


bucketとbrigade


出力フィルタの説明を書こうとすると、bucket brigadeの説明が必要だ。
bucketは辞書を引くとバケツ、と出ている。チャーリーとチョコレート工場に登場する少年の名前でもある。
brigadeは軍隊がらみの用語らしい。旅団とある。師団(division)よりは小さい。と言われても分からない。
今見たWikipediaでは1500~6000名程度の兵員によって構成される部隊、となっている。

bucket型の要素をリング構造で束ねているのが bucket brigadeであるので、バケットの兵員によって構成される部隊、ということかもしれないが、用語の由来はよく分からない。

このbucketにはいろいろな種類がある。
bucketは大きくは、データタイプとメタデータタイプに分類される。
データタイプのbucketには、例えば、ファイルや、ヒープメモリや、mmapメモリや、ソケット等がある。
メタデータタイプのbucketは処理制御用で、データの終端になるEOSや、データの途中でそこまでのデータを強制的に送信させるFLUSHなどがある。
bucketタイプごとにbucketの生成、破棄、読込等の機能が提供されている。
このいろいろなbucketをリング状に繋ぎあわせて構成して、bucket brigadeになる。

そして、この bucket brigadeが出力データの実体だ。
例えば、ヒープメモリタイプのbucketが内部のヒープメモリにHTTPレスポンスヘッダを持ち、
続いて、ファイルタイプのbucketがあり、ファイル名などの情報を持つ。
さらに続いて、EOR(リクエスト終端)のメタデータタイプのbucketがある。
リクエスト処理の進行の中で、ひとつの bucket brigadeにこういった一連のbucketが含まれることになる。


出力フィルタの処理の大雑把な説明


フィルタは階層をなしている。
出力フィルタとは、このbucke brigadeを上流のフィルタから受け取って、これを加工し、下流のフィルタに引き渡すという処理を行っている。
引き渡しの処理を行うのが、ap_pass_brigade()関数だ。


出力フィルタ関数自体は、次のようなプロトタイプを持っている。

(httpd-2.4.9/include/util_filter.h)
134 typedef apr_status_t (*ap_out_filter_func)(ap_filter_t *f,
135                                            apr_bucket_brigade *b);

ap_out_filter_func関数は、受け取ったbucket brigade b を処理し、
処理結果から bucket brigade bbを作成すると、
以下を実行することで、加工した bb を下流の出力フィルタ(f->next)に引き渡す。

ap_pass_brigade(f->next, bb);

最上流のフィルタに最初にbucket brigadeを引き渡すのはContent Geneartorだ。
静的なローカルコンテンツの処理の場合、これは default_handler が行う。

4248 static int default_handler(request_rec *r)
4249 {
 :
4369         status = ap_pass_brigade(r->output_filters, bb);
 :

そして、最下流の出力フィルタはデータをクライアントに向けて送信する役目を担う。
通常は、COREフィルタ、ap_core_output_filter()になる。


出力フィルタ階層の作成


Apache httpdは多くのフィルタ関数を提供している。

RATE_LIMIT出力フィルタは、出力するデータの送信レートを制御する。
HTTP_HEADER出力フィルタは、request_rec構造体にある情報をもとに、送信用のHTTPレスポンスヘッダのbucket brigadeデータを生成する。
DUMPIO_OUT出力フィルタは、受け取ったbucket brigadeの内容を読み込んで、エラーログに出力する。

このほかにも出力フィルタは多数ある。

出力フィルタは ap_register_output_filter()関数でApache httpdプロセス内に登録され、利用可能になる。
この関数で、フィルタ名をキーにしたトライ木 registered_output_filters に出力フィルタ関数が登録される。

登録した出力フィルタ関数は、そのままでリクエスト処理に利用されるわけではない。
適用したいフィルタを実際に適用するには、さらに、ap_add_output_filter()関数やap_add_output_filter_handle()関数で、リクエストの出力フィルタの階層に登録しなくてはならない。

リクエスト処理において、これらの関数により、各フィルタ関数の情報(ap_filter_rec_t 構造体)が、それぞれのフィルタのタイプに従って、コネクション情報(conn_rec構造体)やリクエスト情報(request_rec構造体)に追加される。

Apacheのドキュメントにあるフィルタタイプの説明をかいつまんで訳すと次のような感じになる。

  • コネクションフィルタは、一つの接続の開始から終了までの間有効なもの。
  • プロトコルフィルタは一つのリクエストの間有効となる。
  • リソースフィルタは一つのリソースの処理中有効なものだ。
    これも通常なら一つのリクエスト処理と同じものだが、しかし、Apacheの処理は、一つのリクエスト中にも内部的なリダイレクトや、サブリクエストの処理において処理リソースが変化する。

コネクションフィルタは、コネクション情報(conn_rec構造体)の出力コネクションフィルタ情報(output_filters変数)リスト上に登録される。前述のCOREフィルタは、このコネクションフィルタに属する(厳密にはNETWORKフィルタとなる)。
プロトコルフィルタは、リクエスト情報(request_rec構造体)の 出力プロトコルフィルタ情報(proto_output_filters変数)リスト上に登録される。
最後に、リソースフィルタは、リクエスト情報(request_rec構造体)の 出力フィルタ情報(output_filters変数)リスト上に登録される。

request_rec情報 のoutput_filters情報(出力フィルタ)は、proto_output_filters情報(出力プロトコルフィルタ)に連結しており、さらに、conn_rec情報のoutput_filters情報(出力コネクションフィルタ)に連結して大きなリストを構成している。
個々の出力フィルタは、リスト内ではファイルタイプの小さい順に並ぶことになる。
これが、つまり、出力フィルタの階層だ。
前述した default_handlerが指定しているのが、r->output_filters。rが request_rec情報で、r->output_filtersが出力フィルタの階層の最上位を指すことになる。

4369         status = ap_pass_brigade(r->output_filters, bb);


設定による出力フィルタの追加


registered_output_filters TRIE木にフィルタを登録する処理は、各モジュールやcore機能で初期化処理中に行われる。

これら登録済みの出力フィルタを処理中のリクエスト、コネクションのフィルタリストに登録するのは、CORE出力フィルタのように必要に応じて自動的に登録されるものと、設定によって追加されるものがある。

設定によってフィルタを追加するために使用されるのは、たとえば、SetOutputFilterディレクティブである。
以下の設定例は、 /downloads へのリクエストに対して、 RATE_LIMIT出力フィルタを適用することを定義している。

<Location /downloads>
  SetOutputFilter RATE_LIMIT
  SetEnv rate-limit 400 
</Location>

また、AddOutputFilter ディレクティブでは、ファイルの拡張子ごとにフィルタを設定することができる。
以下の設定例は、拡張子が shtml のリソースを処理する場合に、INCLUDEフィルタを適用し、その後DEFLATEフィルタを適用することを定義している。

AddOutputFilter INCLUDES;DEFLATE shtml

RemoveOutputFilterディレクティブはmAddOutputFilterで追加されたフィルタを、削除する。

以下の設定は、上記のAddOutputFilterで .shtmlのファイルに追加された INCLUDEフィルタ、DEFLATTEフィルタを適用出力フィルタの階層から削除する。

RemoveOutputFilter shtml

Apacheのドキュメントには以下のような複雑な設定例がある。
# Effective filter "DEFLATE"
AddOutputFilter DEFLATE shtml
<Location /foo>
  # Effective filter "INCLUDES", replacing "DEFLATE"
  AddOutputFilter INCLUDES shtml
</Location>
<Location /bar>
  # Effective filter "INCLUDES;DEFLATE", replacing "DEFLATE"
  AddOutputFilter INCLUDES;DEFLATE shtml
</Location>
<Location /bar/baz>
  # Effective filter "BUFFER", replacing "INCLUDES;DEFLATE"
  AddOutputFilter BUFFER shtml
</Location>
<Location /bar/baz/buz>
  # No effective filter, replacing "BUFFER"
  RemoveOutputFilter shtml
</Location>
http://httpd.apache.org/docs/2.4/en/mod/mod_mime.html#addoutputfilter

この例では、結局、 /bar/bas/buzへのリクエストの場合、追加の出力フィルタは登録されないことになる。

2014年4月28日月曜日

mod_info: 設定のダンプ(DUMP_CONFIG)

httpd-2.4では、mod_infoモジュールの機能で、起動時に設定内容のダンプが行えるようになっている。
使い方は簡単で、mod_infoモジュールを読み込むようにしておいて、起動時のオプションに -DDUMP_CONFIG を指定すればよい。

http://httpd.apache.org/docs/2.4/en/mod/mod_info.html#startup

-DDUMP_CONFIG実行例

(httpd.conf)
-------------------------------------------------
LoadModule info_module modules/mod_info.so
-------------------------------------------------

(コマンド実行例)
$ ./httpd -t -DDUMP_CONFIG
# In file: /usr/local/apache249/conf/httpd.conf
#   6:
ServerName www.example.com
#   9:
Listen 80
#  19:
StartServers 1
#  20:
MaxRequestWorkers 3
#  21:
MinSpareThreads 3
#  22:
MaxSpareThreads 3
#  23:
ThreadsPerChild 3
#  24:
MaxConnectionsPerChild 0
#  25:
AsyncRequestWorkerFactor 2
#  41:
KeepAlive on
#  42:
KeepAliveTimeout 5
#  43:
MaxKeepAliveRequests 100
#  50:
LogFormat "%h %l %u %t \"%r\" %>s %b" common
#  51:
CustomLog logs/access_log common
#  60:
LogLevel warn mpm_event:trace6
#  66:
Listen 443
#  71:
SSLRandomSeed startup file:/dev/urandom  256
#  72:
SSLRandomSeed connect builtin
#  74:
SSLSessionCache shmcb:logs/scache(1024000)
#  77:
SSLCryptoDevice builtin
#  81:
SSLFIPS off
#  84:
SSLPassPhraseDialog builtin
#  86:
LogFormat "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" ssl_log
#  88:
<VirtualHost _default_:443>
  #  89:
  ErrorLog logs/ssl_error_log
  #  90:
  CustomLog logs/ssl_access_log ssl_log
  #  92:
  SSLEngine on
  #  95:
  SSLSessionCacheTimeout 300
  #  97:
  SSLCertificateFile conf/server.crt
  #  98:
  SSLCertificateKeyFile conf/server.key
  # 102:
  SSLProtocol all
  # 105:
  SSLCipherSuite HIGH:MEDIUM
  # 108:
  SSLCompression off
  # 111:
  SSLHonorCipherOrder off
  # 114:
  SSLInsecureRenegotiation off
</VirtualHost>
# 153:
ExtendedStatus on
# 155:
<Location /server-status>
  # 156:
  SetHandler server-status
</Location>
# 164:
Alias /cgi-bin /usr/local/apache249/cgi-bin
# 166:
<Directory /usr/local/apache249/cgi-bin>
  # 167:
  SetHandler cgi-script
  # 168:
  Options ExecCGI
</Directory>
Syntax OK

ただし、この出力では、既にIfModuleやIncludeは処理済みなので、出力されない。
.htaccessの内容も出力されない。
ServerRootも出力されないが、これは -DDUMP_RUN_CFG オプションを指定すれば出力される。
LoadModuleも出力されないが、これは -M オプションを指定すれば分かる。

-DDUMP_RUN_CFGの出力例

$ ./httpd -t -DDUMP_RUN_CFG
ServerRoot: "/usr/local/apache249"
Main DocumentRoot: "/usr/local/apache249/htdocs"
Main ErrorLog: "/usr/local/apache249/logs/error_log"
Mutex ssl-stapling: using_defaults
Mutex ssl-cache: using_defaults
Mutex default: dir="/usr/local/apache249/logs/" mechanism=default
PidFile: "/usr/local/apache249/logs/httpd.pid"
Define: DUMP_RUN_CFG
User: name="#-1" id=4294967295 not_used
Group: name="#-1" id=4294967295 not_used

-Mオプションの出力例

$ ./httpd -M
Loaded Modules:
 core_module (static)
 so_module (static)
 http_module (static)
 mpm_event_module (shared)
 unixd_module (shared)
 authz_core_module (shared)
 log_config_module (shared)
 mime_module (shared)
 ssl_module (shared)
 socache_shmcb_module (shared)
 status_module (shared)
 alias_module (shared)
 cgid_module (shared)
 info_module (shared)

ときどき、読み込まれた設定を確認したいことがあり、mod_infoで ?config クエリを使っていたりしたが、 mod_infoのステータス画面の出力設定を残すのが嫌な場合もあった。
これなら起動時に確認され、infoページへのアクセスの設定もないので、都合がよさそうだ。
ただし、今、実行中のプロセスの設定内容を出力させるには、mod_infoの情報ページにアクセスしなくてはならないようだ。

注意点

-DDUMP_CONFIGは読み込んだ設定情報を出力しているだけで、有効な設定だけを出力しているわけではない。
たとえば、設定ファイルに重複した設定があった場合、

StartServers         1
StartServers         10

その内容がそのまま出力される。
$ ./httpd -t -DDUMP_CONFIG
# In file: /usr/local/apache249/conf/httpd.conf
#   6:
PidFile conf/httpd.pid
#   9:
ServerName www.example.com
#  12:
Listen 80
#  22:
StartServers 1
#  23:
StartServers 10
 :


2014年4月21日月曜日

event MPMのタイムアウトキュー

event MPMには4つのタイムアウトキューが存在する。

タイムアウトまでの経過時間別にキューが用意されているため、タイムアウトイベントの登録は、末尾に行われる。登録された順に、タイムアウト時間が経過することになる。キューという呼び名の通り、タイムアウト時刻が経過しているかどうかは先頭から確認される。
タイムアウトの発生前に、待っているイベント(ソケットの受信や送信)が発生すれば、各タイムアウトキューからその情報は除去される。


(1) write_completion_q

  • レスポンスの送信が未完了な場合に利用される。 
  • TimeOut でのタイムアウト待ちキュー。 
  • TimeOut 経過前に書き込み可能になったら、書き込み処理がworkerスレッドで実行される。 
  • TimeOut 経過した場合、ソケットのwrite側をshutdownし、linger_qでクローズ待ちする。 

(2) keepalive_q

  • レスポンス送信完了後の次リクエスト受信待ちに利用される。 
  • KeepAliveTimeOut でのタイムアウト待ちキュー。 
  • KeepAliveTimeOut 経過前に読込可能になったら、リクエスト処理がworkerスレッドで実行される。 
  • KeepAliveTimeOut 経過した場合、ソケットのwrite側をshutdownし、linger_qでクローズ待ちする。 

(3) linger_q

  • ソケットのwrite側のshutdown後の、FIN待ちに利用される。 
  • MAX_SECS_TO_LINGER(30秒) でのタイムアウト待ちキュー 
  • MAX_SECS_TO_LINGER 経過前に読込可能になったら、読み捨て処理を行い、ソケットをクローズする 
  • MAX_SECS_TO_LINGER 経過した場合、ソケットをクローズする 

(4) short_linger_q

  • ソケットのwrite側のshutdown後の、FIN待ちに利用される。 
  • SECONDS_TO_LINGER(2秒) でのタイムアウト待ちキュー 
    • notesに"short-lingering-close"は存在した場合に、linger_qではなく、こちらを使用する。 
    • mod_reqtimeoutで受信タイムアウト時に指定されていた。他は見当たらない。 
  • SECONDS_TO_LINGER 経過前に読込可能になったら、読み捨て処理を行い、ソケットをクローズする 
  • SECONDS_TO_LINGER 経過した場合、ソケットをクローズする


これらのタイムアウト待ちもworker MPMでは、workerスレッド内で待っていたが、event MPMでは、タイムアウトキューに登録し、また、対応するソケットを (centos5では)epollの監視対象に追加し、listenerスレッドで待ち受けを行うようになった。
これにより、workerスレッドの無駄な待ち時間が削減され、結果的に処理効率が改善したと考えられる。
KeepAliveTimeOutの待ち時間以外の改善個所もあることから、KeepAliveを利用していない場合にも性能改善が見られたのはこの効果ではないかと考えている。

ちなみに、KeepAlive Onで実行していると、レスポンスを返した後、ソケットはkeepalive_qに入るが、もしクライアントが直ちにソケットを閉じた場合、listenerスレッドはソケットが読込可能になったことを検知し、workerスレッドに引き渡す。その後、workerスレッドが読み込むと、EOFが検知されることになる。

2014年4月14日月曜日

apr_skiplist とmod_dialupモジュール

httpd-2.4.7で行われている変更:
Changes with Apache 2.4.7

  *) APR 1.5.0 or later is now required for the event MPM.
これがなぜだろう、というblogを見かけた。

同じblogの記事内に、以下のconfig.logのメッセージが紹介されている。
configure:25866: result: no - APR skiplist is not available

したがって、これは、以下の関係だろうと想像された。
Changes for APR 1.5.0
 :

  *) Add apr_skiplist family. [Jim Jagielski]

blogを書かれた方の意図はともかく、少し調べてみるとこれに関連した 2.4系branch の修正は、次のcommitで行われていた。
http://svn.apache.org/viewvc?view=revision&revision=1542560

http://svn.apache.org/viewvc?view=revision&revision=1543475
ここにある、Jeffのアイデアというのはこれだろう。
http://mail-archives.apache.org/mod_mbox/httpd-dev/201311.mbox/%3CCAKUrXK5n7havg2-6MR6JAt0dQecbH6je6K9ySY8iHNQfN6mv8g%40mail.gmail.com%3E


ちなみに、もともとhttpd側で実装していたのを、APRに引っ越させたらしい。
http://svn.apache.org/viewvc?view=revision&revision=1528438
http://svn.apache.org/viewvc?view=revision&revision=1527536
これはどうでもいいか。

2014年4月7日月曜日

event MPM と worker MPM の比較 追加: httperf

Keep-Alive無効の場合も、CPU使用率が worker MPM < event MPM となっていた。
その分、毎秒のリクエスト処理件数も増えているのだと考えられるが、念のため、httperfで固定レートでリクエスト負荷を加えた場合のCPU使用率を比較した。
結果的には、両者のCPU使用率の差は些少だった。
負荷をかけている期間(約100秒)中のCPU使用率の平均は以下の通り。


event MPM worker MPM
%user 13.23 13.09
%nice 0.00 0.00
%system 19.10 18.91
%iowait 0.09 0.09
%steal 0.00 0.00
%idle 67.59 67.92


基本的にリクエスト処理によるCPU負荷は event MPM と worker MPM では大差はない。
event MPM の処理効率が上がっているため、abによる性能検証で、リクエスト処理件数が上がり、処理件数が増えた分、CPU使用率が増大した、ということでよいだろう。

以下 httperfコマンド実行結果をコピペし、投稿末尾に、CPU使用率のグラフをつけた。
特に深い考えはないが、いずれもhttperf は2プロセスで実行した。

(1) event MPM


(1.1) httperf #1

$ ./httperf --server centos5 --port 8080 --uri /hello.html --num-conns 200000 --rate 2000
httperf --client=0/1 --server=centos5 --port=8080 --uri=/hello.html --rate=2000 --send-buffer=4096 --recv-buffer=16384 --num-conns=200000 --num-calls=1
httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE
Maximum connect burst length: 3

Total: connections 200000 requests 200000 replies 200000 test-duration 99.993 s

Connection rate: 2000.1 conn/s (0.5 ms/conn, <=10 concurrent connections)
Connection time [ms]: min 0.4 avg 0.7 max 4.8 median 0.5 stddev 0.1
Connection time [ms]: connect 0.2
Connection length [replies/conn]: 1.000

Request rate: 2000.1 req/s (0.5 ms/req)
Request size [B]: 71.0

Reply rate [replies/s]: min 1999.9 avg 2000.1 max 2000.1 stddev 0.1 (19 samples)
Reply time [ms]: response 0.4 transfer 0.0
Reply size [B]: header 224.0 content 31.0 footer 0.0 (total 255.0)
Reply status: 1xx=0 2xx=200000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 23.85 system 76.08 (user 23.8% system 76.1% total 99.9%)
Net I/O: 636.8 KB/s (5.2*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

(1.2) httperf #2

#  ./httperf --server centos5 --port 8080 --uri /hello.html --num-conns 200000 --rate 2000
httperf --client=0/1 --server=centos5 --port=8080 --uri=/hello.html --rate=2000 --send-buffer=4096 --recv-buffer=16384 --num-conns=200000 --num-calls=1
httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE
Maximum connect burst length: 4

Total: connections 200000 requests 200000 replies 200000 test-duration 99.993 s

Connection rate: 2000.1 conn/s (0.5 ms/conn, <=10 concurrent connections)
Connection time [ms]: min 0.1 avg 0.7 max 4.8 median 0.5 stddev 0.1
Connection time [ms]: connect 0.3
Connection length [replies/conn]: 1.000

Request rate: 2000.1 req/s (0.5 ms/req)
Request size [B]: 71.0

Reply rate [replies/s]: min 1999.9 avg 2000.1 max 2000.1 stddev 0.1 (19 samples)
Reply time [ms]: response 0.4 transfer 0.0
Reply size [B]: header 224.0 content 31.0 footer 0.0 (total 255.0)
Reply status: 1xx=0 2xx=200000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 21.87 system 78.04 (user 21.9% system 78.0% total 99.9%)
Net I/O: 636.8 KB/s (5.2*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0


(2) worker MPM


(2.1) httperf #1

$ ./httperf --server centos5 --port 8080 --uri /hello.html --num-conns 200000 --rate 2000
httperf --client=0/1 --server=centos5 --port=8080 --uri=/hello.html --rate=2000 --send-buffer=4096 --recv-buffer=16384 --num-conns=200000 --num-calls=1
httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE
Maximum connect burst length: 3

Total: connections 200000 requests 200000 replies 200000 test-duration 99.993 s

Connection rate: 2000.1 conn/s (0.5 ms/conn, <=10 concurrent connections)
Connection time [ms]: min 0.4 avg 0.7 max 4.7 median 0.5 stddev 0.1
Connection time [ms]: connect 0.3
Connection length [replies/conn]: 1.000

Request rate: 2000.1 req/s (0.5 ms/req)
Request size [B]: 71.0

Reply rate [replies/s]: min 1999.9 avg 2000.1 max 2000.1 stddev 0.1 (19 samples)
Reply time [ms]: response 0.4 transfer 0.0
Reply size [B]: header 224.0 content 31.0 footer 0.0 (total 255.0)
Reply status: 1xx=0 2xx=200000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 23.74 system 76.18 (user 23.7% system 76.2% total 99.9%)
Net I/O: 636.8 KB/s (5.2*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

(2.2) httperf #2

#  ./httperf --server centos5 --port 8080 --uri /hello.html --num-conns 200000 --rate 2000
httperf --client=0/1 --server=centos5 --port=8080 --uri=/hello.html --rate=2000 --send-buffer=4096 --recv-buffer=16384 --num-conns=200000 --num-calls=1
httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE
Maximum connect burst length: 4

Total: connections 200000 requests 200000 replies 200000 test-duration 99.993 s

Connection rate: 2000.1 conn/s (0.5 ms/conn, <=10 concurrent connections)
Connection time [ms]: min 0.2 avg 0.7 max 4.8 median 0.5 stddev 0.1
Connection time [ms]: connect 0.3
Connection length [replies/conn]: 1.000

Request rate: 2000.1 req/s (0.5 ms/req)
Request size [B]: 71.0

Reply rate [replies/s]: min 1999.9 avg 2000.1 max 2000.1 stddev 0.1 (19 samples)
Reply time [ms]: response 0.4 transfer 0.0
Reply size [B]: header 224.0 content 31.0 footer 0.0 (total 255.0)
Reply status: 1xx=0 2xx=200000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 22.19 system 77.72 (user 22.2% system 77.7% total 99.9%)
Net I/O: 636.8 KB/s (5.2*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

(3)CPU使用率比較


(3.1) event MPM


(3.2) worker MPM


2014年4月1日火曜日

event MPM と worker MPM の比較まとめ

(1) CPU使用率の比較

event MPM > worekr MPM
event MPMではsystem + user で90%以上の値になっている(Keep-Alive有効の方がやや高い)。
worker MPMの場合は、Keep-Alive無効で60%程度、KeepAlive有効だと更に低く50%程度になる。
リクエストの処理件数の違いが現われているんだろう。


Keep-Alive無効 Keep-Alive有効
event MPM worker MPM event MPM worker MPM
%user 36.56 24.19 42.74 23.42
%nice 0.00 0.00 0.00 0.00
%system 53.04 37.66 51.03 25.28
%iowait 0.34 0.27 0.14 0.15
%steal 0.00 0.00 0.00 0.00
%idle 10.06 37.88 6.09 51.14

メモ

そもそも、Keep-Alive有効な状態で、worker MPMがリクエストをどう処理したのか。
今回の設定では、MaxKeepAliveRequestsは指定していない。
したがってデフォルトの100になっている。
100リクエストの処理が終わると、接続が切られ、次のコネクションがworkerスレッドを割り当てられるといった順序で処理が行われていったのだろう。
アクセスログに %k (この接続でのKeep-Aliveなリクエスト処理数) を追加して、値を確認してみると、確かに、100より大きな値は見られなかった。


(2) リクエスト処理数の比較

abでの1秒あたりのリクエストの処理数はKeep-Alive有効、無効いずれの場合もevent MPMの方が優位だった。


(<table>タグがなぜかうまく使えなかったので、絵にした)

ただし、event MPM(Keep-Alive有効)の場合は、リクエストエラーが発生した。
また、残念ながらネットワーク(100Mbps)的にもこのあたりが限界だった。

Keep-Aliveが無効なら、worker MPMとevent MPMで処理に違いがあるとは思わなかったが、実際には差が生じている。workerスレッド数以上に接続を保持できる構成や、ソケットのシャットダウン処理の非同期化が効果を上げているのだろうか。


念のため httperfを用いて固定レートでの負荷をかけてCPU使用率の比較を行った。
これは次回。


(2014/4/3) CPU使用率の比較に表を追加