소프트웨어 개발 및 운영 환경에서 프로세스 응답 없음 현상이 자주 발생하는데, 이로 인해 시스템 성능 저하나 서비스 중단이 발생할 수 있습니다. 본 문서에서는 pstack 도구를 사용하여 프로세스 응답 없음 문제를 진단하고, 프로세스 스택 정보를 분석하여 문제 원인을 파악하고 해결하는 방법을 설명합니다.
배경: 위험 관리 시스템 하위 서비스가 응답하지 않는 상태로 멈춰 위험 관리 서비스를 사용할 수 없게 되었습니다. 서비스 가용성 모니터링 부족으로 인해 프로세스 응답 없음 상황을 즉시 파악하지 못해 시스템이 중단되었습니다.
본문
프로세스 응답 없음은 프로세스가 중단되어 응답하지 않지만 종료되지 않은 상태를 의미합니다. 이는 데드락, 리소스 고갈, 예외 등 다양한 원인으로 발생할 수 있습니다. 이러한 문제를 해결하기 위해 pstack 도구를 사용하여 프로세스의 스택 정보를 분석하고 문제의 근본 원인을 파악할 수 있습니다.
단계
pstack은 일반적으로 gdb(GNU 디버거)와 함께 제공되는 유용한 도구입니다. 다음 명령어를 통해 설치할 수 있습니다:
sudo apt-get install gdb
프로세스 ID 획득: 먼저, 응답하지 않는 프로세스의 프로세스 ID(PID)를 얻어야 합니다. ps 명령어를 사용하여 모든 프로세스를 나열하고, 문제 해결이 필요한 프로세스 ID를 찾을 수 있습니다. pstack 도구를 사용하여 프로세스 스택을 분석할 수 있습니다. 프로세스 ID를 얻은 후에는 pstack 도구를 사용하여 해당 프로세스의 스택 정보를 가져올 수 있습니다. 다음 명령어를 실행하세요:
pstack <PID>
이 프로세스의 스택 정보를 출력하여 현재 실행 중인 함수 호출 시퀀스를 보여줍니다. 이러한 정보를 분석하면 프로세스가 멈춘 위치를 파악하고 문제를 진단할 수 있습니다.
스택 정보를 분석하면 프로세스가 멈추는 원인을 파악할 수 있습니다. 데드락, 무한 루프 또는 기타 예외 상황이 발견될 수 있으며, 잠금 해제나 코드 로직 수정 등 구체적인 상황에 맞는 조치를 취해야 합니다.
사례
간단한 데모인데, 메인 함수 실행 후 서브 스레드를 새로 생성하고 실제 실행 함수가 무한 루프에 들어가 프로그램이 정상적으로 종료되지 않고 멈춰버리는 상태입니다
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
프로세스 응결의 원인은 데드루프이며, 메인 스레드가 데드루프에 진입하면 서브 스레드가 종료되지 않아 프로세스가 응결됩니다