例えばこんなのとかですね。
$ sudo grep libssl.so.1.0.1e /proc/*/maps | cut -d/ -f3 | sort -u | xargs -r -- ps ufプロセスを再起動すれば、更新されたライブラリが使用されるという認識で居るのだけれど、実際にそうなのか調べたことがなかった。
ライブラリをアップデートしたときに、どのタイミングで差し変わるか気になったので調べてみた。
共有ライブラリのサンプル
プロセス再起動時
まずは、普通に再起動を行ってみる。
別のターミナルで maps を参照してみる。$ ./test Hell World PID is 16856 Press Any Key To Exit...
libexample.soを更新してみます。$ grep libexample /proc/16856/maps 7fee12576000-7fee12577000 r-xp 00000000 00:0f 14844378 /usr/local/lib64/libexample.so 7fee12577000-7fee12776000 ---p 00001000 00:0f 14844378 /usr/local/lib64/libexample.so 7fee12776000-7fee12777000 r--p 00000000 00:0f 14844378 /usr/local/lib64/libexample.so 7fee12777000-7fee12778000 rw-p 00001000 00:0f 14844378 /usr/local/lib64/libexample.so
$ ./test Hello World PID is 17109 Press Any Key To Exit...
まあ、普通に更新されますね。$ grep libexample /proc/17109/maps 7f33b9223000-7f33b9224000 r-xp 00000000 00:0f 14844450 /usr/local/lib64/libexample.so 7f33b9224000-7f33b9423000 ---p 00001000 00:0f 14844450 /usr/local/lib64/libexample.so 7f33b9423000-7f33b9424000 r--p 00000000 00:0f 14844450 /usr/local/lib64/libexample.so 7f33b9424000-7f33b9425000 rw-p 00001000 00:0f 14844450 /usr/local/lib64/libexample.so
他のプロセスがライブラリをロードした状態で、更新する
プロセスAで libexample.so を使用した状態で、libexample.so を更新し、プロセスBを起動する。 そのときプロセスBは、古いライブラリと新しいライブラリのどちらを使用することになるのか。プロセスA
プロセスAは起動させたままで、ライブラリを更新する。$ ./test Hell World PID is 17248 Press Any Key To Exit...
プロセスBを起動する。$ vim libexample.c $ make $ sudo make install
このとき maps は以下のようになる。$ ./test Hello World PID is 17343 Press Any Key To Exit...
libexample.so が置き換わってるので古いのを利用しているプロセスは (deleted) がつく。$ grep libexample /proc/*/maps 2> /dev/null /proc/17248/maps:7f707a138000-7f707a139000 r-xp 00000000 00:0f 14844464 /usr/local/lib64/libexample.so (deleted) /proc/17248/maps:7f707a139000-7f707a338000 ---p 00001000 00:0f 14844464 /usr/local/lib64/libexample.so (deleted) /proc/17248/maps:7f707a338000-7f707a339000 r--p 00000000 00:0f 14844464 /usr/local/lib64/libexample.so (deleted) /proc/17248/maps:7f707a339000-7f707a33a000 rw-p 00001000 00:0f 14844464 /usr/local/lib64/libexample.so (deleted) /proc/17343/maps:7f9413f52000-7f9413f53000 r-xp 00000000 00:0f 14844475 /usr/local/lib64/libexample.so /proc/17343/maps:7f9413f53000-7f9414152000 ---p 00001000 00:0f 14844475 /usr/local/lib64/libexample.so /proc/17343/maps:7f9414152000-7f9414153000 r--p 00000000 00:0f 14844475 /usr/local/lib64/libexample.so /proc/17343/maps:7f9414153000-7f9414154000 rw-p 00001000 00:0f 14844475 /usr/local/lib64/libexample.so
fork時
fork した子プロセスでライブラリの関数を利用するプログラムを用意します。 1秒ごとに子プロセスを生成して、その間にライブラリを更新します。プログラムは起動したまま、ここでライブラリを差し替え。$ ./test-fork [Parent] PID is 18271 [Parent] Hell World [Child] Hell World [Child] PID is 18272 [Child] Hell World [Child] PID is 18273 [Child] Hell World [Child] PID is 18274
プログラムの出力を見てみると、$ vim libexample.c $ make $ sudo make install
変わらず "Hell" のままですね。[Child] Hell World [Child] PID is 18276 [Child] Hell World [Child] PID is 18277 [Child] Hell World [Child] PID is 18279 [Child] Hell World [Child] PID is 18280
細かな動作までは調べてないので推測ですが、fork() の場合は動的にリンクされたあとのメモリ空間をコピーするためではないかと思います。
まとめ
- 共有ライブラリをアップデートしたときはプロセスの再起動が必要
- 子プロセスの再起動だけでは不足
- 同じ共有ライブラリを他のプロセスで利用していたとしても、新しく起動したプロセスでは更新後の共有ライブラリが利用される
備考
今回は試してないですが、Dynamic Loadingというライブラリを動的にロードする方式がありこの場合どのような動作になるのかが気になります。
恐らく dlopen/dlclose で開き直せば新しいライブラリがロードされるのではないかと思いますが..
Dynamic Loading は恐らく Apache のモジュールのロードで利用されてるはずです。
nginx ではビルド時に組み込むはずなので、Dynamic Loading ではないはず。
恐らく dlopen/dlclose で開き直せば新しいライブラリがロードされるのではないかと思いますが..
Dynamic Loading は恐らく Apache のモジュールのロードで利用されてるはずです。
nginx ではビルド時に組み込むはずなので、Dynamic Loading ではないはず。