2010年03月03日

Apache 2.3/2.4系の新機能を見てみよう その3 〜MPMの動的ロード〜

はてなブックマークに登録

Apache 2.3の特長を探る

さて、Apache 2.3探索シリーズの第3回になります今回、MPM(Multi-Processing Modules)に話題を移します。

従来Apache 2.0/2.2ではMPMはconfigureでのオプション指定によって選択し、ビルドでスタティックリンクされます。そのため、もしMPMを変える場合はconfigureでの指定を変えてビルドする所からやり直しになります。2.3/2.4からはこれがApacheモジュールと同じようにLoadModuleディレクティブで実行時に選ぶことができるようになるそうです。

この仕組みを利用する為には、前回のビルドでのconfigureオプションに項目を1つ追加する必要があります。--enable-mpms-sharedオプションを追加し、引数にallを与えてもう一度ビルド&インストールしてみましょう。

$ configure --help
...
  --enable-mpms-shared=MPM-LIST
                          Space-separated list of MPM modules to enable for
                          dynamic loading. MPM-LIST=list | "all"
...
$ ./configure --enable-mpms-shared=all --enable-mods-shared=all \
  --with-included-apr --prefix=/usr/local/app/apache-2.3.5 \
  --with-mysql

なお、httpd本体にスタティックリンクされたモジュールは-lオプション指定での起動で確認することができますね。

$ /usr/local/app/apache-2.3.5/bin/httpd -l
Compiled in modules:
  core.c
  mod_so.c
  http_core.c
  event.c      ← MPM

たとえば、前回のビルド版のhttpdでは上記のような結果になりますが、これを今回新たに--enable-mpms-sharedオプションを追加したビルド版ですと、event MPMがスタティックリンクから外れます。

$ /usr/local/app/apache-2.3.5/bin/httpd -l
Compiled in modules:
  core.c
  mod_so.c
  http_core.c

起動にはMPMの指定が必要ですが、LoadModuleディレクティブを以下のように追加して行います。

LoadModule mpm_event_module    modules/mod_mpm_event.so

さてこのMPM周り、どう変わったのでしょうか。2.2.14と2.3.5-alphaの間でhttpdのmain()を持つserver/main.cのdiffを取ってMPMを呼び出す箇所を検証してみましょう。

***************
*** 737,743 ****
  
          ap_run_optional_fn_retrieve();
  
!         if (ap_mpm_run(pconf, plog, server_conf))
              break;
  
          apr_pool_lock(pconf, 0);
--- 766,772 ----
  
          ap_run_optional_fn_retrieve();
  
!         if (ap_run_mpm(pconf, plog, ap_server_conf) != OK)
              break;
  
          apr_pool_lock(pconf, 0);

ap_mpm_run()からap_run_mpm()へと関数名が変わったようです。

2.2系ではap_mpm_run()関数が各MPMにて実装されていて、これをスタティックリンクすることでserver/main.cからMPMの処理へと移行させていました。

server/mpm/prefork/prefork.c (v2.2.14)
    912 /*****************************************************************
    913  * Executive routines.
    914  */
    915 
    916 int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
    917 {
    918     int index;
    919     int remaining_children_to_start;
    920     apr_status_t rv;
    921 
    922     ap_log_pid(pconf, ap_pid_fname);
    923 
    924     first_server_limit = server_limit;
    925     if (changed_limit_at_restart) {
    926         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    927                      "WARNING: Attempt to change ServerLimit "
    928                      "ignored during restart");
    929         changed_limit_at_restart = 0;
    930     }
    ...
   1258 
   1259     return 0;
   1260 }

それが2.3系ではap_run_mpm()関数に名前が変わっています。この関数名でgrepで全ソースを検索してみてもどこにも見当たりません。実は、ap_run_mpm()という関数はマクロによって生成されているので、その関数名のままではソース上から見つけることはできません。

include/ap_mpm.h (v2.3.5-alpha)
    82  /**
    83   * Pass control to the MPM for steady-state processing.  It is responsible
    84   * for controlling the parent and child processes.  It will run until a
    85   * restart/shutdown is indicated.
    86   * @param pconf the configuration pool, reset before the config file is read
    87   * @param plog the log pool, reset after the config file is read
    88   * @param server_conf the global server config.
    89   * @return DONE for shutdown OK otherwise.
    90   */
    91  AP_DECLARE_HOOK(int, mpm, (apr_pool_t *pconf, apr_pool_t *plog, server_rec *server_conf))

このマクロを展開するとap_run_mpm()関数と一緒にap_hook_mpm()関数も用意されます。ap_hook_...という関数名はApacheモジュールの開発経験があれば一度は目にしたことのある方ばかりかと思います。

お分かりのように、ap_hook_xxx()関数は各イベントフックにイベントハンドラを登録する関数です。一方ap_run_xxx()関数は、同じxxxの名前を持つイベントフックを起動する役割を持ちます。つまり、2.3系からは直接MPM内の関数をリンクしての呼び出しではなく、イベントフックの仕組みに基づいて"mpm"イベントフックを定義し、このイベントハンドラとしてMPMの処理に委譲する形をとるようになったのです。

server/mpm/event/event.c (v2.3.5-alpha)
   2718 static void event_hooks(apr_pool_t * p)
   2719 {
   2720     /* Our open_logs hook function must run before the core's, or stderr
   2721      * will be redirected to a file, and the messages won't print to the
   2722      * console.
   2723      */
   2724     static const char *const aszSucc[] = { "core.c", NULL };
   2725     one_process = 0;
   2726 
   2727     ap_hook_open_logs(event_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST);
   2728     /* we need to set the MPM state before other pre-config hooks use MPM query
   2729      * to retrieve it, so register as REALLY_FIRST
   2730      */
   2731     ap_hook_pre_config(event_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
   2732     ap_hook_check_config(event_check_config, NULL, NULL, APR_HOOK_MIDDLE);
   2733     ap_hook_mpm(event_run, NULL, NULL, APR_HOOK_MIDDLE);
   2734     ap_hook_mpm_query(event_query, NULL, NULL, APR_HOOK_MIDDLE);
   2735     ap_hook_mpm_note_child_killed(event_note_child_killed, NULL, NULL, APR_HOOK_MIDDLE);
   2736     ap_hook_mpm_register_timed_callback(event_register_timed_callback, NULL, NULL,
   2737                                         APR_HOOK_MIDDLE);
   2738     ap_hook_mpm_get_name(event_get_name, NULL, NULL, APR_HOOK_MIDDLE);
   2739 }
   ...
   2844 module AP_MODULE_DECLARE_DATA mpm_event_module = {
   2845     MPM20_MODULE_STUFF,
   2846     NULL,                       /* hook to run before apache parses args */
   2847     NULL,                       /* create per-directory config structure */
   2848     NULL,                       /* merge per-directory config structures */
   2849     NULL,                       /* create per-server config structure */
   2850     NULL,                       /* merge per-server config structures */
   2851     event_cmds,                 /* command apr_table_t */
   2852     event_hooks                 /* register_hooks */
   2853 };

event MPMの内容を見ると、AP_MODULE_DECLARE_DATA構造体mpm_event_moduleで、当モジュールが読み込まれたときに呼び出されるコールバック関数event_hooks()関数を登録しています。このevent_hooks()中で、他のApacheモジュールでも見受けられたようにap_hook_xxx()関数によってイベントフックを設定しています。その中にap_hook_mpm()関数の呼び出しもあります。

LoadModuleディレクティブによってこのモジュールがロードされると、即座にこのevent_hooks()関数が呼び出されます。そこでap_hook_mpm()関数によりevent_run()関数がハンドラとして登録され、ap_run_mpm()関数が呼び出された際に起動されるのです。

ではこのイベントフックの仕組みと言うのは、そもそもどのような実装になっているのでしょう。次回は番外編として、イベントフックの実装詳細を確認し、現行の2.2系も含めたApacheイベントフックの仕組みそのものをおさらいしていきたいと思います。上に出たap_hook_mpm()/ap_run_mpm()両関数を生成するAP_DECLARE_HOOKマクロについて、その展開の仕組みを追う所から入ります。

klab_gijutsu2 at 03:42│Comments(0)TrackBack(0)

トラックバックURL

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
Archives
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント