今回は、systemdの初期化時間を短縮するチューニング方法を解説する。systemdのデフォルト値は、汎用のLinuxディストリビューションを想定しているため、必ずしもWSLでの利用に最適化されていない。ここでは、初期化時間の長いユニットを探し、不要なユニットを削除するための方法を解説する。
なお、systemdの基本的なことに関しては、前々回記事「第18回 systemd 基本編」および前回記事「第19回 systemd コマンド編」を参照されたい。
なお、評価には、Windows 11 Ver.22H2とWSLディストリビューションとしてはUbuntu(22.04.2 LTS)を利用した。Linuxカーネルのバージョンは、5.15.90.1-microsoft-standard-WSL2である(写真01)。
systemd-analyzeコマンド
systemdの起動時間の詳しい調査には、systemd-analyzeコマンドが利用できる。このコマンドは、起動時の統計情報やその他の情報を解析して要約した情報を提供するためのものである。systemdが動作しているときのLinuxシステムの起動時の振る舞いや処理時間などを調べるには、これを使う。
また、このコマンドから得られた調査すべきユニットの情報などに関しては、前回解説したsystemdコマンドを利用する。
systemd-analyzeコマンドは、サブコマンドでさまざまな機能を実行できる。表01は利用に必要な最低限のサブコマンドだ。systemd-analyzeには、多数のサブコマンド、オプションがあるが、これだけは最低限理解しておく必要がある。その他のサブコマンドやオプションに関しては、“--help”オプションを使うか、manページを参照されたい。
サブコマンドを省略するとtimeサブコマンドが指定されたとみなされる。このコマンドでは、対象となったユニットがすべて起動されるまでの経過時間を測定する。
最も時間がかかっている起動経路を探すには、critical-chainサブコマンドを使う。これは、起動処理の中で、依存関係にあり、最も時間の掛かっている経路を探すものだ。赤で表示される部分が経路の中でも初期化に時間を要しているものになる。
systemdログの表示
起動に時間がかかるユニットでは、エラーが起きていることがある。こうしたユニットの起動を調べるには、systemdのログファイルを調べる。
systemdのログファイルは、journalctlコマンドでみることが可能だ。(表02)に最低限覚えるべきjournalctlのサブコマンド、オプションを示す。なお、すべてのオプションや詳細な解説については、「--help」オプションやmanページを参照してほしい。また、インターネット内にもjournalctlに関する解説記事は多数ある。
journalctlコマンドで特定のユニットについて調べるには、
journalctl␣--unit="networkd*"␣--no-hostname␣--boot=0
※␣は半角スペースを示す
とする。なお、このコマンドは「journalctl␣-u␣"networkd*"␣--no-hostname␣-b」のような省略形が利用できる。
メッセージが長く、ターミナルの端をはみ出すようなら、時刻を省略して表示する「--output=cat」オプションを追加する。
systemdのログは、起動時に取得されるため、ログの記録には、複数回の再起動時のログが入っている。-bあるいは「--boot」オプションは、ログ範囲を再起動ごとに指定するもの。「--boot␣0」は、直近の再起動時のログにjournalctlの出力を限定するもの。「-b」は、その省略形で、パラメーターのbootidを省略すると直近の再起動を表す「0」が仮定される。
初期化時間を調べるとき
初期化時間を調べる場合、一回WSL自体を停止させたほうがよい。そのためには、PowerShellなどWSL外から「wsl.exe --shutdown」を実行する。
また、systemdは、さまざまなシステムサービスの起動に使われているため、ユニットやサービスを停止してしまうと、WSLディストリビューション自体が動作しなくなる可能性もある。操作は慎重に行うべきだが、WSLの場合、再インストールを行うことで、完全な初期状態に戻すことは可能だ。ただし、WSL内で行った設定やファイルなどはすべて消えてしまう。このため、バックアップを行っておくか、実行イメージをコピーして実験用のディストリビューションを作成しておくといいだろう。このあたりに関しては、過去記事(「第16回 WSLのバックアップとリストア」 や、「第17回 WSLのバックアップとリストア 応用編」を参考にしてほしい。
初期化時間の長いサービスを無効化
systemdの初期化に要した時間は、「systemd-analyze」コマンドを使う。オプションなしで起動すれば、初期化時間を表示する(写真02)。Ubuntuディストリビューションの場合、筆者の環境では2.5秒ほどかかっている。この時間は、WSLの起動時間に影響するため、これを短くすることで、WSLの起動時間を短縮できる。
最も時間がかかっている一連のユニットを探すには、「systemd-analyze critical-chain」コマンドを使う。このコマンドでは、最も時間がかかった、依存関係にあるユニットによる経路(chain)が表示される。このうち赤で表示されているのが時間がかかっているコマンドである。また、ツリーの先頭に表示されるのは、systemdの起点となるユニット(ターゲット)である。
これをみると、「snap」や「snapd」関連のユニットが時間を使っているようだ。この状態では、snapやsnapdが何であるのかが分からない。まずはユニットを調べてみよう。まずは、最も先頭にある“snapd.seeded.service”だ。
以下のコマンドを使い、ユニットファイルを表示させる(写真03)。
systemctl␣cat␣snapd.seeded.service
※␣は半角スペースを示す。以下同様
ユニットファイルの実行設定(ExecStart)に「/usr/bin/snap」というコマンドがある。
“snap”というコマンドがあるようなので、manページがないか探す。それには「man␣-k␣snap」とする。まさにsnapというmanページがあるのでこれを「man snap」で表示させてみる(写真04)。
それによれば、snapはディストリビューションに依存しないパッケージの管理プログラムのようだ。とりあえず、snapコマンドのヘルプを実行してみる(写真05)。基本的なオプションとして“list”、“info”などがあるようだ。情報表示のコマンドであれば、システム状態を変更する可能性は低いと考えられるので試しに「snap list」を実行してみる(写真06)。すると5つほどのsnapが組み込まれているようだ。それぞれは、「snap info」で詳細をみることができる。
これらのコマンドから得られた情報としては、snap自体は動作しているが、特にシステム関連の機能をインストールしているわけでもなさそうだ。
もし、「snap」や「snapd」がaptパッケージマネージャーで管理されているなら、アンインストールは容易である。これを調べて見る。
「apt␣list␣--installed␣--all-versions␣"snap"」とすることで“snapd”を含むパッケージを検索できる(写真07)。
aptパッケージマネージャで管理されているなら、万一、あとで必要になった場合でも、戻すことも難しくない。問題なさそうなので、「sudo␣apt␣remove␣snapd」としてアンインストールしてみる。
その後、再度起動状態を確認するには、WSLを一回完全に終了させる。それには、PowerShellなどWin32側で「wsl --shutdown」とする。
再度WSLを起動して「systemd-analyze」コマンドを使うと、起動時間は400ミリ秒まで短縮されている(写真08)。
さらに追求してみるが……
今度は、“networkd-dispatcher.service”がクリティカルパスになっている。networkdは、systemdの一部となるネットワーク関連のサービスである。ただし、WSL2のネットワークは、仮想マシン側で管理されているため、WSLディストリビューション側からほとんど制御する必要はない。何か問題があるかもしれないのでログを確認しておく。
journalctl␣-b␣-u␣networkd-dispatcher.service
これによれば、lo(ローカルループバック・ネットワークデバイス)やeth0(ネットワーク)でエラーが出ている。
networkdに関しては、専用の管理コマンドnetworkctlがある。サブコマンドなしで起動すると、現在の状態を表示する(写真09)。これによると、networkd自体が動作していないようである。WSLでは、ネットワークをVM側で管理しているため、ディストリビューション側からの制御が行えないためだと考えられる。なので、ログにloやeth0でエラーが記録されていたと考えられる。そして、対象となるネットワークデバイスがないため、networkdが動作していないと考えられる。
networkdが動作していないので「networkd-dispatcher.service」を止めても大丈夫であろう。
sudo␣systemctl␣disable␣networkd-dispatcher.service
上記コマンドを実行後、再起動して、同様に調べると初期化時間は348ミリ秒(348 ms)とあまり短くなっていない(写真10)。これ以上は、手間をかけてもわずかな時間しか短縮できなさそうだ。また、残りのサービスの名称にsystemdがあり、systemd全体に影響も出そうなので、このあたりでやめておくべきだろう。
systemd関連のコマンドを使うことで、systemdの初期化の効率化が可能で、それにより、systemd使用時の起動時間を短縮することもできる。ただし、理解しておいてほしいのは、WSLではsystemdはまだ必須というわけでもないため、systemd自体を無効化して起動時間を短縮する方法もあることだ。
> Windows Subsystem for Linuxガイド 連載バックナンバー
https://news.mynavi.jp/tag/winsubsystem/