クラッシュダンプからカーネルメッセージを取り出すツール「crashdmesg」を作りました
Linuxカーネルには、カーネルパニック時にkexecを使ってダンプ取得用のカーネル(セカンドカーネル)を起動する仕組みがあります。
このセカンドカーネルは予めリザーブされたメモリ内で起動するため、クラッシュしたカーネルが処理していたメモリの内容はそのまま残っていて、procファイルシステム経由でクラッシュダンプを取得する事ができます。
このDSASブログでも、以前「Linuxでクラッシュダンプを採取(1) 〜 kexec + kdump を使ってみる 〜」と言うタイトルでクラッシュダンプの取得方法をご紹介しました。
「crashdmesg」は、kexec+kdumpで保存したクラッシュダンプから、カーネルメッセージの内容を取り出すツールです。
デバッガと比べてはるかに軽量なため、セカンドカーネル上で直接/proc/vmcoreからカーネルメッセージを取り出すこともできます。
最近のクラッシュダンプ事情
クラッシュダンプにはサーバ上のメモリの内容がほとんど保存されているため、カーネルメッセージのほか、クラッシュ時に稼働していたプロセスやネットワークの状態など、多くの情報を取得することができます。
カーネルパニックでサーバがダウンした場合、syslog等でのカーネルメッセージの転送は間に合わず、ログが全くない状態で原因究明を行わなければならないことが多く、クラッシュダンプを取得する仕組みは、カーネルに起因するトラブル解析の強い味方です。
しかし、クラッシュダンプを取得する方法にはデメリットもあります。
サーバの搭載メモリのほぼ全てをダンプするため、クラッシュダンプのサイズも搭載メモリに合わせて大きくなり、保存に時間がかかるのです。
例えば弊社では、メモリを72GB搭載して運用しているサーバがあり、この場合では72GB近いダンプファイルをローカルディスクもしくはネットワーク上の他のサーバに転送する必要があります。
転送が終わるまでは、サーバの再起動や調査を行うことができず、復旧が遅れてしまいます。
最小限のダウンタイムで情報集め
そもそも、巨大なダンプファイルを転送する時間がないのであれば、セカンドカーネル上でクラッシュダンプを解析してしまい、結果だけを転送するという方法を思いつきました。
クラッシュダンプを解析するcrashコマンドに、予めカーネルメッセージのダンプや、プロセス、ネットワーク状態等の状況を出力するスクリプトを実行させて、結果のテキストデータだけを転送するという作戦です。
パニックのメッセージやスタックトレースの出力に応じたデバッグはできなくなりますが、カーネルのバグフィックス情報を調べる手がかりぐらいは読み取れるのではないかと考えたのです。
しかし、crashコマンドを実行するには、100MB近いサイズになるデバッグシンボル付きのカーネルが必要になるほか、crashコマンドの実行自体もかなりのメモリを必要とします。
セカンドカーネルは予めリザーブした領域上で動くため、非常時にcrashコマンドを実行するためだけに多量のメモリをリザーブするわけにもいかず断念しました。
crashdmesg
そこで思い切って、取得する情報をカーネルメッセージのバッファ領域だけに絞り、カーネルダンプファイルから直接情報を取得することができないか調べてみました。
すると、いくつかのシンボル情報が取得出来れば、クラッシュダンプからカーネルメッセージのバッファ領域を拾うことができそうだと分かり、「crashdmesg」というツールを作ってみました。
その名のとおり、dmesgコマンドのクラッシュダンプ版をイメージしていて、/proc/vmcoreもしくは引数に指定したダンプファイルからカーネルメッセージをダンプして標準出力に出力します。
軽量なプログラムですので、セカンドカーネル上の僅かなメモリの中でも使うことができます。
しかも、ダンプに必要なシンボル情報をvmcore内から読み取るため、デバッグシンボル付きのカーネルやSystem.mapを用意する必要がありません。
最後に
crashdmesgのソースコードは、githubで公開しています。
https://github.com/hiro-dSn/crashdmesgcrashdmesgの仕組み解説や、kexec+kdump使用のコツなども、追ってこのDSASブログに掲載したいと思います。