Apache の mod_cgid と surrogate parent model について

monit のデッドロックを追っていた件から派生して、 pthread 全然知らんなーということで表紙がきもちわるいことで有名な(?) 『Pthreadsプログラミング』を読んでました。


Pthreadsプログラミング

Pthreadsプログラミング


「5.5.1 スレッドのからのforkの呼び出し」の章で、スレッドから fork する際の注意点が書かれています。その中で 代理親モデル surrogate parent model という用語が気になったのでピックアップ。

代理親モデル surrogate parent model

代理親モデルを検討する

代理親モデル ( surrogate parent model) では、プログラムは初期化の時点でひとつの子プロセスをフォークする。子の唯一の目的は、オリジナルプロセスが別の子をフォークする必要がある時に、ある種の「代理親」として働くことである

『Pthreadsプログラミング』P214 から引用

これだけだと抽象的でよくわからないのですが、身近なところだと Apache の MPM worker で CGI を実行する際に使う mod_cgid というモジュールがこのモデルにのっとって実装されています。

ここで CGI の話をしよう

「え いとうさん いきなり CGI の話ですか 」
「それはあなた、わたしがホスティングやってる会社に勤めているからですよ」
「ろりぽっぷ!へてむる!ろりぽっぷ!へてむる!」

Apache の mod_cgid

mod_cgid を図解すると下記の様なモデルになっています

  • Apache 起動時に cgidデーモンが fork される
  • worker と cgidデーモンは UNIXドメインソケットでプロセス間通信する
  • マルチスレッドな worker に変わって cgidデーモンが fork + exec を担う
    • cgid が 子プロセスを抱える = surrogate parent

CGIを実行中にプロセスツリーを取ってみると ↓ のようになります。

root     23330  0.0  0.4 173684  3928 ?        Ss   17:42   0:00 /usr/sbin/httpd.worker
apache   23332  0.0  0.2 173532  2584 ?        S    17:42   0:00  \_ /usr/sbin/httpd.worker
apache   23531  0.0  0.1  25568  1416 ?        S    17:42   0:00  |   \_ /usr/bin/perl /var/www/html/index.pl
apache   23533  0.0  0.1  25568  1416 ?        S    17:42   0:00  |   \_ /usr/bin/perl /var/www/html/index.pl
apache   23536  0.0  0.1  25568  1420 ?        S    17:42   0:00  |   \_ /usr/bin/perl /var/www/html/index.pl
apache   23538  0.0  0.1  25568  1424 ?        S    17:42   0:00  |   \_ /usr/bin/perl /var/www/html/index.pl
apache   23541  0.0  0.1  25568  1420 ?        S    17:42   0:00  |   \_ /usr/bin/perl /var/www/html/index.pl
apache   23333  0.0  0.6 714552  5816 ?        Sl   17:42   0:00  \_ /usr/sbin/httpd.worker
apache   23334  0.0  0.6 714552  5860 ?        Sl   17:42   0:00  \_ /usr/sbin/httpd.worker

プロセス名がみな同じなので区別がつきにくいですが、perl の子プロセスを生やしているのが cgid = surrogate parent なプロセスですね。cgid は Apacheが起動してマルチスレッド化する前にfork されるので子プロセスの中で一番若い pid を取得します。

surrogate parent

surrogate parent model で検索すると、リアルな子育て的なトピック( 代理の親が子育てするとあーだのこーだの...) ばっかりみつかってスレッドのお話の方はあんまりでてきません ...
一応 openldap (slapd) の ML が見つかったりはしましたが、どうも広く使われているような用語ではなさそうですね

名前はともかく、このようなモデルがあるのだなーというのが大事ですね。

mod_cgi と mod_cgid

「あれ、CGIってリクエストを受けている Aapcheプロセス自身が fork するんじゃなかったけ? 」というあなた、それは MPM prefork + mod_cgi ですね。mod_cgid とは別実装なのでした。

まとめ

マルチスレッドの制約があるため mod_cgid はやけに複雑な実装になってんるんだろうなー、と前々から気になってはいたのでしたが具体的な理由がよく分かって ませんでした。 本を読んで スレッド + fork 時の落とし穴を避けるためであることが明確になりすっきり。