2014年12月7日日曜日

Apacheモジュールのアップデート時にrestartは必要か

Apacheのモジュールをアップデートしたときに通常は再起動を行っていますが、そもそも再起動が必要なのか、gracefulだけで大丈夫だったりしないかということを調べてみました。

Apacheのモジュールロードのタイミング

モジュールをロードするコードはこのあたりだろうか。

https://github.com/apache/httpd/blob/2.4.10/modules/core/mod_so.c
https://github.com/apache/httpd/blob/2.4.10/modules/core/mod_so.c

Apache からは APR の apr_dso_load() を使っているみたいなので、APRの方を覗いてみる。
https://github.com/apache/apr/blob/1.5.1/dso/unix/dso.c

複数のOSをサポートするために #ifdef が多用されててちょっと見にくいが、Linux環境であれば dlopen() が使用されるようだ。

さて、dlopen() が使用されるということが分かったので、呼び出し元に戻る。
最初に提示したコードは load_module() の中に記述されている。
これはどこからコールされているのかというと、同じ mod_so.c の中にある。



AP_INIT_TAKE2は引数を二つもつディレクティブで、
RSRC_CONFは, の外に記述するという意味のようです。
最後の EXEC_ON_READ は名前からも推測できますが、設定が読み込まれたときに実行されます。
実行するのは二つ目の引数である load_module() です。

設定が読み込まれたときに実行されると言うことは、graceful でも大丈夫な気がします。

モジュールをアップデートしてみる

graceful でも大丈夫そうということが分かったので、実際に試してみます。
mod_hello という簡単なモジュールを作ってみます。
上記のGistの mod_hello は Hello という設定がコンフィグに出てくると、第一引数の文字列をエラーログに出力するだけのものです。
インストールは apxs で行います。
$ apxs -c mod_hello.c
$ sudo apxs -i -a -n hello mod_hello.la 
httpd.conf に設定を追加します。
+LoadModule hello_module modules/mod_hello.so
+Hello world
Apache を起動します。
$ sudo apache2ctl start
 * Starting apache2 ...
[Sun Dec 07 16:11:41.528152 2014] [:notice] [pid 24998] Hello world
エラーログに "Hello world" と表示されました。
続いて、モジュールを書き換えてみます。

mod_hello.c の21行目を "Hello %s" から "Hell %s" にしてみます。
再度、モジュールをコンパイル・インストールし、graceful してみます。
$ apxs -c mod_hello.c
$ sudo apxs -i -a -n hello mod_hello.la
$ sudo apache2ctl graceful
 * Gracefully restarting apache2 ...
[Sun Dec 07 16:30:57.456100 2014] [:notice] [pid 25436] Hell world
変わりました。

結論

  • モジュールをアップデートするときは graceful で十分

参考文献

追記(2015/02/01)

mod_proxy では設定が反映されなかったりすることもあるそうで、graceful だと不十分な場合もあるようです。
共有メモリを使うようなモジュールだと古い設定がそのまま使われるとかありそうなので、モジュールの中身次第では注意が必要そうです。