2014年3月3日月曜日

eventMPM: AsyncRequestWorkerFactor

次にevent MPM固有の設定を見る。
リンクはここ。
http://httpd.apache.org/docs/2.4/en/mod/event.html


AsyncRequestWorkerFactor


このディレクティブは2.4系で追加になっている。

ドキュメントをなんとなく訳してみる

event MPMは接続を非同期に処理する。
ここで、リクエスト処理スレッド(ワーカスレッド)は短期間の間、必要に応じて割り当てられ、
そして、一つのリクエスト処理スレッドと一緒の別の接続がコネクション毎に確保される。
※後半は意味不明だが、昔のドキュメントには接続に対して「(多くはSSL)」と注釈されているので、接続がリクエスト処理スレッドを占有するworker MPMと同じタイプのものを指しているようだ。つまり、2種類のタイプがあるってことだろう。

この結果、次のような状況になる。
全てのワーカが拘束され、確立した非同期接続のための新しい処理を行う処理スレッドがない。

この問題を緩和するために、event MPMは2つのことをする

1つめ。
プロセスごとに受け付ける接続数をアイドル状態のワーカスレッド数に応じて制限する

2つめ。
全てのワーカスレッドがビジー状態の場合、Keep-Alive状態の接続をクローズする。
これは、Kee-Aliveタイムアウトに至る前の接続であっても、クローズする。
これにより、それぞれのクライアントは別の、ワーカスレッドが利用できるプロセスに再接続することができる。

このディレクティブがプロセス毎の接続数の制限を細かく調整するために使用される。
プロセスが現在の接続数(クローズ中のものを除く)が下記の値より小さい場合にのみ新しい接続を受け付ける。
ThreadsPerChild + (AsyncRequestWorkerFactor * number-of-idle-workers)

これは、同時接続数の最大値が以下の値となることを意味している
(AsyncRequestWorkerFactor + 1 )*MaxRequestWorkers

AsyncRequestWorkerFactorは非整数値を取れる(例: 1.5)


以上が訳文。
次に、休み休み考えてみる。
接続には以下があるだろう。

 [A] 実際にワーカスレッドで処理中の接続
    (1)非同期処理中
    (2)同期処理中(2.4.7より前の場合は、SSL接続が該当したようだ)
 [B] Kee-Alive中などworker処理のない接続
    (1)非同期処理待ち(リクエスト受信待ち、write許可待ち)
    (2)クローズ中

[A]の数は処理中のワーカスレッド数に他ならないから、
[A]<=ThreadPerChild となる。

もし [A]+[B}<=ThreadPerChildとするのであれば、[B]接続に対応するワーカスレッドがアイドル状態でなくてはならない。
しかし、それはKeep-Alive中の接続のためにワーカスレッドを使わず、予約しているわけで、eventMPMの意味がない。
当然のこととして、空いているワーカスレッドがあるなら、接続を受け入れるべきだと考えるだろう。

そう考えても、がんがん受け入れると、どんどん[B]の数が増えていく。
そこで、

[A]+[B(1)] < ThreadsPerChild + ( AsyncRequestWorkerFactor * idle_workers(アイドルワーカ数) )

という制限を設けた。
※ちなみに、B(2)の接続は最終的なクローズ処理をlistener_threadで行っているので、アイドルワーカを必要としない。

つまり、どの程度余分に接続を受け入れるのかを調整する設定値ということになるだろう。
値が大きいほど余分に接続を受け付けることができる。

ただし、受付接続数が増えるのはアイドル状態のワーカスレッドがいる場合だ。
アイドルワーカがいない場合、当然、すべてのワーカスレッドは処理中なので、かりに接続数がThreadsPerChild(個)であっても([B]の接続がない状態)、これ以上の新規接続は受け付けない(接続数は増えない)。

接続からリクエストを受け取り、即座にレスポンスが返され、そのままKeep-Aliveになる場合、瞬間瞬間にはアイドルワーカが発生するので、新規接続を受け付けることが可能になる。
多くのリクエストを処理していれば、瞬間瞬間のアイドルワーカも減少してくる。
あるいは、リクエストの処理に要する時間が長くなると、やはり、時々刻々のワイドルワーカ数が平均的には減少する。
その場合、受け入れられる接続数の合計は抑制的になるだろう。

そして、Keep-Alive接続上に次のリクエストが到着したとき、もしアイドルワーカがいなければ、event MPMは接続を切ってしまう。
多過ぎる数の接続を受け付けている場合には、こういった事態も起こりやすいだろう。
AsyncRequestWorkerFactor を程よく設定するのは、ちょっと考える必要がありそうだ。

ところで実装を見ると、
 [A]+{B(1)] > ThreadsPerChild + ( AsyncRequestWorkerFactor * idle_workers(アイドルワーカ数) )
の場合には、新たな接続を受けつけないようになっているので、
 [A]+{B(1)] <= ThreadsPerChild + ( AsyncRequestWorkerFactor * idle_workers(アイドルワーカ数) )
という関係になるはずだ。


(httpd-2.4.7/server/mpm/event/event.c)
   1571         else if (  (int)apr_atomic_read32(&connection_count)
   1572                - (int)apr_atomic_read32(&lingering_count)
   1573              > threads_per_child
   1574                + ap_queue_info_get_idlers(worker_queue_info) *
   1575                  worker_factor / WORKER_FACTOR_SCALE)
   1576         {
   1577           if (!listeners_disabled)
   1578               disable_listensocks(process_slot);
   1579           ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
   1580                        "Too many open connections (%u), "
   1581                        "not accepting new conns in this process",
   1582                        apr_atomic_read32(&connection_count));
   1583           ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
   1584                        "Idle workers: %u",
   1585                        ap_queue_info_get_idlers(worker_queue_info));
   1586           listeners_disabled = 1;
   1587         }



  • connection_countは接続数。
  • lingering_countはクローズ中の接続数(connection_countに含まれる)。
  • apr_atomic_read32()は引数のアドレスに格納されている値をアトミックに取得する関数。
  • threads_per_childはThreadsPerChildの設定値。
  • ap_queue_info_get_idlers(worker_queue_info)はアイドルワーカ数が取得する関数。
  • worker_factorはAsyncRequestWorkerFactorの設定値のWORKER_FACTOR_SCALE倍の値を非負整数で保持している。
  • WORKER_FACTOR_SCALEは定数16。
  • ( worker_factor / WORKER_FACTOR_SCALE )が元のAsyncRequestWorkerFactorの設定値。ただし、AsyncRequestWorkerFactorは分母が16の分数の精度で保持されている。

このelse if 条件を満たすと、新たな接続を受け付けなくなる。
なぜdoubleとかで元の設定値を保持しないのか、意味があるのだろうが、分かっていない。

0 件のコメント:

コメントを投稿