Linux Magic SysRqキー:フリーズしたサーバーをデータ損失なしで安全に復旧・再起動する方法

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

深夜2時の本番環境フリーズ:SSHが応答しなくなったとき

時刻は深夜2時14分。プライマリPostgreSQLノードで未処理の504 Gateway Timeoutが発生したと、ページャーがけたたましくアラートを鳴らします。ターミナルを立ち上げ、ssh [email protected]を実行しますが、何の反応もありません。最初のハンドシェイクのまま接続が無限にハングアップしてしまいます。

状況を確認しようと必死になり、クラウドプロバイダーのアウトオブバンドVNCやIPMIコンソールを開きます。しかし画面は完全にフリーズしており、点滅するカーソルと140を超えて上昇し続けるロードアベレージが表示されたまま停止しています。カーネルパニックのスタックトレースすら発生していません。制御不能なメモリリークや深刻なI/Oボトルネックによってリソースが枯渇し、ユーザー空間が完全に麻痺しているのです。

マウスカーソルがハイパーバイザー管理画面の赤い「強制リセット」ボタンへと向かいます。しかし、そのボタンを押してはいけません。強制電源断を行うと、未書き込みのページキャッシュが瞬時に数メガバイト消失します。処理中だったデータベースのトランザクションは中途半端にコミットされた状態となり、わずか30秒の再起動で済むはずが、45分に及ぶext4のジャーナルリプレイやInnoDBテーブルスペースの破損対応へと早変わりしてしまいます。Linuxカーネルには、はるかに安全な緊急脱出手段が用意されています。それが「Magic SysRqキー」です。

基本概念:SysRqがクラッシュしたユーザー空間をバイパスする仕組み

Linuxがフリーズした際、その原因はほぼ常にユーザー空間のソフトウェアにあります。sshdやsystemd、シェルといったデーモンがスケジューラのタイムスライスを割り当てられなくなったり、割り込み不可能なディスクスリープ(状態D)で待機したままスタックしたりすることが原因です。

一方、Linuxカーネル自体は通常正常に動作し続けています。ハードウェアタイマーを処理し、低レベルのキーボード割り込みにも引き続き応答可能です。

Magic SysRqは、この割り込みレイヤーに直接フックします。SysRqシグナルを送信すると、キーボードドライバーまたは仮想端末のシリアルバスが、実行権限を直接カーネルコアのハンドラに渡します。これらのルーチンは即座に実行され、CPUの過負荷、メモリページの不足、シェルの無応答などをすべて無視して処理されます。

SysRqビットマスク:制御値の理解

SysRqはメモリ内容のダンプや任意のプロセスの強制終了が可能なため、本番環境向けのディストリビューションでは制限されていることが一般的です。Linuxでは、/proc/sys/kernel/sysrqのビットマスクを使用してアクセスを制御します:

  • 0: SysRqを完全に無効化。
  • 1: すべての機能を有効化。
  • 2: コンソールのログレベル調整を許可。
  • 4: キーボード制御(SAKおよびunrawモード)を許可。
  • 8: プロセスおよびCPUのデバッグダンプを許可。
  • 16: 緊急同期(sync)コマンドを許可。
  • 32: ファイルシステムの読み取り専用再マウントを許可。
  • 64: プロセスへのシグナル送信(SIGTERMおよびSIGKILL)を許可。
  • 128: 緊急再起動および電源オフを許可。
  • 256: リアルタイムタスクの優先度調整(nice)を許可。

これらの値はビット加算して組み合わせます。例えば、値を176(16 + 32 + 128)に設定すると、ダーティバッファの同期、ファイルシステムの読み取り専用再マウント、再起動のトリガーが許可されます。この組み合わせにより、機密性の高いメモリダンプコマンドをブロックしつつ、安全なクラッシュリカバリに必要な機能のみを確保できます。

復旧シーケンス:REISUB

フリーズしたシステムを安全にシャットダウンするには、定番の語呂合わせ「Raising Elephants Is So Utterly Boring(象を育てるのは本当に退屈だ)」を覚えておきましょう。各文字は、カーネルが直接処理する段階的なシャットダウンパイプラインに対応しています:

  1. R (unRaw): キーボードドライバーをrawモード(X11やWaylandが使用)からXLATEモードへ戻し、基本的なキーボード入力を復旧します。
  2. E (tErminate): PID 1を除く全プロセスにSIGTERM(シグナル15)を送信し、各デーモンがバッファをフラッシュして正常終了できるようにします。
  3. I (kIll): 終了要求を無視して残留したプロセスを強制終了するため、SIGKILL(シグナル9)を一斉送信します。
  4. S (Sync): メモリ上のダーティキャッシュをNVMe、SSD、またはHDDへ直接フラッシュします。
  5. U (Unmount): 不正な書き込みを防ぎ、ジャーナルフラグのクリーンな状態を保証するため、すべてのアクティブなストレージパーティションを読み取り専用として再マウントします。
  6. B (reBoot): マザーボードのコントローラーを経由して、即座にハードウェアリセットをトリガーします。

実践ガイド:SysRqの有効化と実行

ステップ1:SysRqの確認と有効化

まず、現在のSysRqのパーミッションレベルを確認します:

cat /proc/sys/kernel/sysrq

DebianやUbuntuのサーバーイメージでは、デフォルトで176や438に設定されていることがよくあります。セキュリティが強化されたクラウドAMIの多くでは、これが0や16まで制限されています。詳細なトラブルシューティングのために完全な制御が必要な場合は、一時的にすべての機能を有効化します:

sudo sysctl -w kernel.sysrq=1

今後の再起動後もこの変更を永続化させるには、専用のsysctl設定ファイルを記述します:

echo "kernel.sysrq = 1" | sudo tee /etc/sysctl.d/99-sysrq.conf
sudo sysctl --system

セキュリティポリシーへの配慮も忘れないでください。対象ノードがマルチテナントワークロードを処理していたり、コンプライアンス対象のデータを扱っていたりする場合は、メモリダンプコマンドを制限するために1ではなく176または244を使用してください。

ステップ2:キーボードまたはアウトオブバンドコンソールからの緊急復旧

ローカルキーボード、AWSシリアルコンソールセッション、またはIPMI KVMが利用可能な場合は、生のキーストロークとしてシーケンスを送信します。AltキーとSysRqキー(物理的にはPrint Screenキーと共有されている場合が多い)を長押ししながら、各文字を順番に入力します。システムが各処理を完了できるよう、キー入力の間には必ず間隔を空けてください:

Alt + SysRq + R  (2秒待機 - キーボードがXLATEモードに切り替わる)
Alt + SysRq + E  (10秒待機 - MySQL、Nginx、Redisなどのフラッシュと終了を待つ)
Alt + SysRq + I  (5秒待機 - ハングしたDステートタスクや残留プロセスを強制終了する)
Alt + SysRq + S  (10秒待機 - コンソールに「Emergency Sync complete」が表示されるのを確認)
Alt + SysRq + U  (5秒待機 - 「Emergency Remount R/O」の完了メッセージを待つ)
Alt + SysRq + B  (システムが即座に再起動)

実行中はコンソールログを注意深く監視してください。Sを押した際、未書き込みのダーティページが掃き出されるにつれてディスクI/Oの数値が跳ね上がるのが確認できるはずです。Sの直後に焦ってBを押すと手順が台無しになります。ストレージコントローラーが書き込みキューを完全にクリアするまで十分な時間を与えてください。

ステップ3:コマンドラインおよび自動化によるSysRqの実行

サーバーが完全にダウンしているわけではなく、極端に動作が重くなっているだけの場合もあります。暴走したcronジョブによってロードアベレージが80を超え、SSHセッションの応答にキー入力1回あたり2秒かかるような状況です。rootプロンプトが操作できる状態であれば、カーネルの仮想エンドポイントである/proc/sysrq-triggerに直接トリガーをパイプで渡すことができます。

安全な自動再起動を実行するには、以下のスクリプトを実行します:

#!/usr/bin/env bash
# sysrq-trigger経由で応答低下したサーバーを安全に再起動する

set -euo pipefail

echo "プロセスにSIGTERMを通知しています..."
echo e > /proc/sysrq-trigger
sleep 10

echo "残留プロセスを強制終了しています..."
echo i > /proc/sysrq-trigger
sleep 3

echo "ファイルシステムバッファをストレージにフラッシュしています..."
echo s > /proc/sysrq-trigger
sleep 10

echo "ファイルシステムを読み取り専用で再マウントしています..."
echo u > /proc/sysrq-trigger
sleep 5

echo "カーネル再起動をトリガーしています..."
echo b > /proc/sysrq-trigger

ステップ4:再起動前のクラッシュ診断情報の抽出

再起動によって当面のダウンタイムは解消されますが、貴重な手がかりまで失われてしまいます。もしマシンが個別のSysRqトリガーを受け付けられる程度に応答可能であれば、サーバーを落とす前に簡単なテレメトリ情報を収集しておきましょう:

# 現在のRAM割り当て、スラブデータ、スワップ統計をダンプ
echo m > /proc/sysrq-trigger

# 実行可能タスク、バックトレース、ブロックされたロックをダンプ
echo t > /proc/sysrq-trigger

# 保持されているすべてのCPUロック一覧をダンプ(lockdepのサポートが必要)
echo d > /proc/sysrq-trigger

これらのコマンドはカーネルリングバッファに直接書き込みを行います。マシンが復旧したら、journalctl -k -b -1で永続化されたジャーナルログを確認するか、アウトオブバンドシリアルログを精査して障害の原因を特定してください。

安全な復旧手順は、いかなる場合も強制リセットに勝る

フリーズしたサーバーの電源をいきなり落とすのは一見手っ取り早い解決策に見えますが、突然の電源断の後に発生する障害対応には何時間もの調査時間を費やすことになりかねません。適切にチューニングされたSysRqビットマスクを導入すれば、OSの他の部分が完全に沈黙していても機能するアウトオブバンド管理チャネルを確保できます。REISUBのシーケンスをしっかりと記憶し、インフラ全体に適切なsysctlのデフォルト設定を適用して、次の深夜の緊急対応を冷静かつクリーン、そして確実なものにしましょう。

Share: