メインコンテンツへスキップ
見出し画像

【基礎から学び直すITインフラ入門】#10 Linux基礎③ - プロセスとシグナル

    この記事では、Linuxのプロセスとシグナルについて解説します。
    このあたりからインフラ屋ではない私にとって、若干あやふやな部分がでてきそう。。。前回記事は ↓ から

    はじめに

    前回は、Linuxのディレクトリ構造とパスの概念について学びました。ディレクトリの階層構造や、絶対パスと相対パスの違いを理解できたと思います。
    今回は、プロセスとシグナルについて学びます。Linuxではこのプロセスをどのように管理し、制御しているのか、 また、シグナルとは何かを理解することで、サーバーで動いているプログラムを適切に管理できるようになります。

    プロセスとは

    プロセスは、プログラムが実際にメモリ上で実行されている状態のことです。プログラムが起動されると、プロセスが生まれます。
    ※プログラムは、ディスク上に保存されている実行可能なファイルで、例えば、Webサーバーソフトウェアのnginxなどが該当します。

    プロセスID(PID)

    Linuxでは、起動した各プロセスにプロセスID(PID) という一意の番号が割り振られます。この番号を使って、プロセスを識別したり、操作したりします。
    PIDは1から順番に割り振られ、システムが起動して最初に実行されるプロセスのPIDは常に1です(通常はsystemdやinitというプロセスが割り当てられます)。

    親プロセスと子プロセス

    Linuxでは、あるプロセスが別のプロセスを起動することができます。このとき、起動した側を親プロセス、起動された側を子プロセスと呼びます。
    この親子関係を辿っていくと、最終的には全てのプロセスがPID 1のプロセス(通常はsystemd)に行き着きます。つまり、Linuxのプロセスは木構造(ツリー構造) になっています。この親子関係の全体像をプロセスツリーと呼びます。

    # プロセスツリー
    systemd (PID: 1)
    ├─ sshd (PID: 500)
    │  └─ sshd (PID: 1234)
    │     └─ bash (PID: 1235)
    │        └─ vim (PID: 1300)
    ├─ nginx (PID: 600)
    │  ├─ nginx worker (PID: 601)
    │  └─ nginx worker (PID: 602)
    └─ mysqld (PID: 700)

    親プロセスが終了すると、通常は子プロセスも終了します。ただし、親が死んでも子プロセスが生き残る場合もあり、その場合は孤児プロセスとなってPID 1に引き取られます。

    プロセスの確認

    ps - プロセスの一覧表示

    現在動いているプロセスを確認するには、psコマンドを使います。

    # 全ユーザーのプロセスを詳細表示
    ps aux
    
    # 出力例:
    USER       PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
    root         1  0.0  0.1 168548 12000 ?     Ss   10:00   0:01 /sbin/init
    root       500  0.0  0.0  72304  3200 ?     Ss   10:00   0:00 /usr/sbin/sshd
    hiro      1235  0.0  0.1  21460  5000 pts/0 Ss   10:30   0:00 -bash
    hiro      1300  0.5  0.2  25800  8000 pts/0 S+   11:00   0:10 vim memo.txt
    
    # オプション解説:
    # a  他ユーザーの実行プロセスも含める
    # u  詳細表示
    # x  端末に依存しないプロセスも含める
    # つまり、このマシン上で動いている全プロセスとなる。

    主な列の意味:
    USER
    : プロセスを実行しているユーザー
    PID: プロセスID
    %CPU: CPU使用率
    %MEM: メモリ使用率
    COMMAND: 実行しているコマンド
    STAT: プロセスの状態(後述)

    top / htop - リアルタイム監視

    psは実行した瞬間の断面ですが、topやhtopはリアルタイムでプロセスの状態を監視できます。

    top - 11:30:00 up 1 day,  2:30,  1 user,  load average: 0.00, 0.01, 0.05
    Tasks: 150 total,   1 running, 149 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  0.3 us,  0.2 sy,  0.0 ni, 99.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    MiB Mem :   3934.0 total,   2500.0 free,    800.0 used,    634.0 buff/cache
    MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.   2900.0 avail Mem
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
     1300 hiro      20   0   25800   8000   2000 S   0.3   0.2   0:10.50 vim
        1 root      20   0  168548  12000   8000 S   0.0   0.3   0:01.00 systemd
      500 root      20   0   72304   3200   2500 S   0.0   0.1   0:00.20 sshd

    プロセスの状態

    プロセスには、いくつかの状態があります。psコマンドのSTAT列や、topのS列に表示されます。

    主な状態:
    R (Running)
    : 実行中、またはCPUを待っている状態
    S (Sleeping): 何かのイベント(入力待ちなど)を待っている状態。ほとんどのプロセスはこの状態です。
    D (Uninterruptible Sleep): 割り込み不可能なスリープ状態。通常はディスクI/O待ちです。
    T (Stopped): 一時停止状態
    Z (Zombie): ゾンビプロセス。すでに終了しているが、親プロセスがまだ終了を確認していない状態

    プロセスとスレッドの違い

    プロセスと似た概念にスレッドがあります。
    プロセスは、独立したメモリ空間を持つ実行単位です。各プロセスは互いに干渉せず、独立して動作します。
    スレッドは、プロセス内の実行単位です。1つのプロセスが複数のスレッドを持つことができ、同じメモリ空間を共有します。
    プロセスは重いが独立性が高く、スレッドは軽いが干渉のリスクがあるため、実行する処理によって使い分ける必要があります。

    シグナル

    シグナルは、プロセスに対して送る通知や指示のことです。プロセスを終了させたり、一時停止させたり、設定を再読み込みさせたりするために使います。Linuxには様々な種類のシグナルがあり、それぞれ異なる意味を持っています。

    主要なシグナル

    SIGTERM (15): 終了要求
    プロセスに終了してくださいを指示するシグナルです。プロセスは、このシグナルを受け取ると、開いているファイルを閉じたり、接続を切断したりといった後片付けをしてから終了します。

    SIGKILL (9): 強制終了
    プロセスを問答無用で強制終了させるシグナルです。プロセスはこのシグナルを無視できず、即座に終了します。後片付けは一切行われません。
    ※ SIGTERMで終了しないプロセスに対して、最後の手段としてSIGKILLを使います。

    SIGHUP (1): ハングアップ
    元々は端末との接続が切れたことを通知するシグナルでしたが、現在では「設定ファイルを再読み込みしてください」という意味で使われることが多いです。
    例えば、nginxの設定ファイルを変更した後、SIGHUPを送ることで、サーバーを再起動せずに設定を反映できます。

    SIGINT (2): 割り込み
    プロセスを中断させるシグナルで、Ctrl+Cを押したときに送られます。

    SIGSTOP (19) / SIGCONT (18): 一時停止と再開
    SIGSTOPでプロセスを一時停止し、SIGCONTで再開します。

    killコマンド - シグナルの送信

    プロセスにシグナルを送るには、killコマンドを使います。
    また、プロセス名を使ってシグナルを送ることもできます。

    # プロセスID 1300 に SIGTERM を送る(デフォルト)
    kill 1300
    
    # 明示的にSIGTERMを指定
    kill -15 1300
    # または
    kill -TERM 1300
    
    # SIGKILLで強制終了
    kill -9 1300
    # または
    kill -KILL 1300
    
    # SIGHUPを送って設定再読み込み
    kill -HUP 1300
    # または
    kill -1 1300
    
    # プロセス名を指定して実行
    pgrep nginx  # PIDを確認
    pkill nginx

    ※名前に反して、killコマンドは必ずしも殺すわけではなく、様々なシグナルを送るための汎用コマンドです。

    バックグラウンド実行

    フォアグラウンドとバックグラウンド

    通常、コマンドを実行すると、そのコマンドが終了するまでターミナルが占有されます。これをフォアグラウンド実行と呼びます。
    一方、コマンドをバックグラウンドで実行すると、ターミナルを占有せず、他のコマンドを実行できます。

    # フォアグラウンドで実行(ターミナルが占有される)
    sleep 100
    
    # バックグラウンドで実行(すぐにプロンプトが返る)
    sleep 100 &

    &を付けると、そのコマンドはバックグラウンドで実行されます。

    jobs - バックグラウンドジョブの確認

    # バックグラウンドジョブの一覧表示
    jobs
    
    # 出力例:
    [1]+  Running                 sleep 100 &
    [2]-  Running                 find / -name "*.log" &

    fg / bg - フォアグラウンド/バックグラウンドの切り替え

    # 実行中のプロセスを一時停止(Ctrl+Z)
    # (例: vimを編集中)
    ^Z
    [1]+  Stopped                 vim memo.txt
    
    # バックグラウンドで再開
    bg
    
    # フォアグラウンドに戻す
    fg

    nohup - ログアウト後も実行を継続

    通常、ターミナルからログアウトすると、そこで起動したプロセスは全て終了します。しかし、nohupコマンドを使うと、ログアウト後もプロセスを継続できます。

    # ログアウト後も実行を継続
    nohup ./long_running_script.sh &
    
    # 出力は nohup.out に保存される

    これは、時間のかかる処理をサーバーで実行する際に使われます。

    まとめ

    今回は、Linuxのプロセスとシグナルについて学びました。
    プロセスの確認(ps / top)や、killコマンドによるシグナル送信は、実務でも頻繁に使用される基本操作です。本記事を通して、それぞれのコマンドや仕組みの意味を整理できたのではないでしょうか。
    また、プロセスの状態や、フォアグラウンド・バックグラウンド、ジョブ制御などを理解することで、サーバー上で動作するプログラムの扱い方がよりイメージしやすくなったと思います。
    個人的にも、業務上使っていたわけですが、言語化することで曖昧になっていたそれぞれの知識が整理できた気がしてよいですね。
    ここまでで、Linuxの基本的な仕組み(ディレクトリ・プロセス)を一通り押さえました。
    次回は、Linuxの根幹であるファイルシステムについて解説します。ファイルやディレクトリがどのように管理されているのかを理解し、より実践的な操作につなげていきます。

    あなたへのおすすめ