ソフトウェア開発および運用において、プロセスがフリーズしてしまう状況は頻繁に発生します。この状態はシステム性能の低下やサービスの停止を引き起こす可能性があります。本稿では、pstackツールを使用してプロセスフリーズの問題を診断する方法について解説します。プロセスのスタック情報を分析することで、問題の原因を特定し解決策を見つけ出すことができます。
背景:リスク管理システムの子サービスでフリーズが発生し、リスク管理サービスが利用不可となりました。可用性監視の欠如により、プロセスフリーズの状態を早期に検知することができず、システム全体が停止するという事態に至りました。
本文
プロセスのフォジー(ゾンビプロセス)とは、プロセスが応答を停止しているにもかかわらず、終了していない状態を指します。この状況は、デッドロック、リソースの枯渇、例外など、さまざまな原因によって引き起こされる可能性があります。これらの問題に対処するためには、pstack
ツールを使用してプロセスのスタック情報を分析し、根本原因を特定することができます。
ステップ
pstack
は一般的なツールで、通常は gdb
(GNU デバッガ) と共に提供されます。以下のコマンドでインストールできます:
sudo apt-get install gdb
プロセスのIDを取得する: まず、スタックされたプロセスのプロセスID (PID) を取得する必要があります。ps
コマンドを使用してすべてのプロセスをリストし、調査対象のプロセスIDを見つけます。
pstack
ツールを使ってプロセスのスタック情報を分析します。プロセスIDを取得したら、以下のコマンドを実行してスタック情報を取得できます:
pstack <PID>
これにより、現在の呼び出しシーケンスで実行中の関数が示されたプロセスのスタック情報が出力されます。この情報を分析することで、プロセスが停止した場所を特定し、問題の診断に役立てることができます。
スタック情報を分析する: スタック情報を確認することで、プロセスがスタック状に停止している原因を見つけることができます。ロックによる競合状態、無限ループ、またはその他の異常な状況などが見つかる可能性があります。具体的な状況に応じて、適切な対策(ロックの解放、コードロジックの修正など)を講じてください。
実行例
簡単なデモで、main
関数が起動した後、新しいスレッドを作成し、実際の関数を実行することで無限ループに陥り、プログラムが正常に終了できず、偽の停止状態になります。
cmake_minimum_required(VERSION 3.0.0)
project(pstack_main VERSION 0.1.0 LANGUAGES C CXX)
include(CTest)
enable_testing()
# スレッドライブラリを検索
find_package(Threads REQUIRED)
add_executable(pstack_main main.cpp)
# スレッドライブラリへのリンク
target_link_libraries(pstack_main PRIVATE Threads::Threads)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
#include <iostream>
#include <thread>
#include <chrono>
void infiniteLoop() {
while (true) {
// メインスレッドが無限ループに陥る
}
}
int main() {
std::thread thread(infiniteLoop); // 無限ループを実行する関数を持つスレッドを作成
thread.join(); // スレッドの終了を待つ
return 0;
}
プログラムを実行し、pstack
の結果を確認します。
Thread 2 (Thread 0x7eff3619b700 (LWP 1315017)):
#0 infiniteLoop () at /root/pstack/main.cpp:6
#1 0x0000000000402ca9 in std::__invoke_impl<void, void (*)()> (__f=@0x2260eb8: 0x4029a6 <infiniteLoop()>) at /usr/include/c++/8/bits/invoke.h:60
#2 0x0000000000402b02 in std::__invoke<void (*)()> (__fn=@0x2260eb8: 0x4029a6 <infiniteLoop()>) at /usr/include/c++/8/bits/invoke.h:95
#3 0x0000000000403150 in std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul> (this=0x2260eb8) at /usr/include/c++/8/thread:244
#4 0x0000000000403126 in std::thread::_Invoker<std::tuple<void (*)()> >::operator() (this=0x2260eb8) at /usr/include/c++/8/thread:253
#5 0x000000000040310a in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run (this=0x2260eb0) at /usr/include/c++/8/thread:196
#6 0x00007eff36bceb23 in execute_native_thread_routine () from /lib64/libstdc++.so.6
#7 0x00007eff36ea91ca in start_thread () from /lib64/libpthread.so.0
#8 0x00007eff361d58d3 in clone () from /lib64/libc.so.6
Thread 1 (Thread 0x7eff372e1740 (LWP 1315016)):
#0 0x00007eff36eaa6cd in __pthread_timedjoin_ex () from /lib64/libpthread.so.0
#1 0x00007eff36bceda7 in std::thread::join() () from /lib64/libstdc++.so.6
#2 0x00000000004029d2 in main () at /root/pstack/main.cpp:13
プロセスが偽の停止状態になっているのは、無限ループに入っているためで、メイン