韩国保姆2_少女伦理电影_HD中文字幕在线观看,玩偶姐姐在线观看高清,8090新视觉电影免费播放在线观看,98蜜桃

沃趣科技技術社區
行業前沿信息一網打盡
技術社區 > 故障分析|看Linux如何判斷系統“死機”

故障分析|看Linux如何判斷系統“死機”

2023年06月14日

前言



在系統的日常運維中,最令人頭疼的莫過于各種應用程序或者操作系統hung住不響應的問題。對于處在用戶態的程序相對來說還比較容易排查,而一旦程序hung在內核態或者操作系統本身hung住,kill信號甚至硬件中斷都無法響應,此時我們能做的就只有重啟了。然而重啟并不能解決根本問題,更麻煩的是這種情況下我們幾乎拿不到任何有用的信息,后續原因的分析和排查更是步履維艱。好在Linux內核早已提供了一系列的機制來幫助我們分析此類問題。下面我們就來看下如何配置使用這些機制以及它們的實現原理。



不可中斷睡眠


■概念


?  第一種比較常見的現象是:進程長時間處于D(不可中斷睡眠)狀態。依賴于它的進程也會因為等待它而阻塞。那么什么是D狀態呢?顧名思義:首先它是一種睡眠狀態,也就意味著處于此狀態的進程不會消耗CPU。其次睡眠的原因是因為等待某些資源(比如鎖或者磁盤IO),這也是我們看到非常多D狀態的進程都處在處理IO操作的原因。最后一點就是它不能被中斷,這個要區別于“硬件中斷”的中斷,是指不希望在其獲取到資源或者超時前被終止。因此他不會被信號喚醒,也就不會響應kill -9這類信號。這也是它跟S(可中斷睡眠)狀態的區別。


??進程進入D狀態發生在內核代碼或者底層驅動代碼中,典型的場景是與硬件進行通信。通常情況下我們可以通過top命令觀察到進程快速的的進入退出D狀態,但當硬件故障或者驅動bug出現時就會導致進程長時間處于D狀態無法退出,依賴或等待它的其他進程都被阻塞卡死。


  • 處于D狀態的進程

1.jpg


■機制


??內核通常會創建一個khungtaskd的守護進程,它會周期性的檢查所有進程的狀態和上下文切換,進而判斷是否有進程長時間處于D狀態。我們可以通過配置如下內核參數來控制檢測的超時時間、告警打印,以及是否觸發panic,以幫助問題的后續分析。


# 超時時間
kernel.hung_task_timeout_secs = 120
# 告警打印的次數
kernel.hung_task_warnings = 10
# 是否觸發系統panic
kernel.hung_task_panic = 0
# 檢測的最大進程數,系統中進程數超過此值時會忽略超出的部分
kernel.hung_task_check_count = 4194304


  • 進程處于D狀態的超時打印

2.jpg


■實現


    khungtaskd對應的代碼在hung_task.c中,主要實現邏輯:

  1. 每隔一段時間(hung_task_timeout_secs定義的超時時間),檢查系統中所有進程

  2. 針對處于D狀態的進程,記錄并檢查它的上下文切換次數,如果和上次記錄的上下文切換次數相同,則說明此進程在超時時間內一直處于D狀態。

  3. 根據配置選擇打印告警并觸發系統panic


static int __init hung_task_init(void)
{
   ... ...
   watchdog_task = kthread_run(watchdog, NULL, "khungtaskd");    //創建khungtaskd進程
 ... ...
}

static int watchdog(void *dummy)
{
 ... ...
   for ( ; ; ) {
       while (schedule_timeout_interruptible(timeout_jiffies(timeout)))    //休眠一段時間
           timeout = sysctl_hung_task_timeout_secs;
       ... ...
       check_hung_uninterruptible_tasks(timeout);    //開始檢查進程
   }
}

static void check_hung_task(struct task_struct *t, unsigned long timeout)
{
   unsigned long switch_count = t->nvcsw + t->nivcsw;    //計算上下文切換次數
   ... ...

   if (switch_count != t->last_switch_count) {        //和上次切換次數進行比較
       t->last_switch_count = switch_count;
       return;
   }
   ... ...

   printk(KERN_ERR "INFO: task %s:%d blocked for more than "        //打印告警
               "%ld seconds.\n", t->comm, t->pid, timeout);
   printk(KERN_ERR "\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
               " disables this message.\n");

 ... ...
   if (sysctl_hung_task_panic) {
       trigger_all_cpu_backtrace();
       panic("hung_task: blocked tasks");    //觸發系統panic
   }
}



軟鎖和硬鎖


■概念


??另外一種比較常見的情況就是:一個進程一直占用CPU,其他進程始終無法被調度執行,極端情況下甚至無法響應中斷,此時系統可能就會完全hung住不響應任何用戶操作。這種情況還是發生在內核代碼或者驅動代碼bug中。應用程序不會出現這個問題,就好像我們寫一個死循序程序不會導致系統hung住一樣。


??要理解這種情況,首先得明白Linux是個搶占式內核,進程之間可以相互搶占CPU,其次Linux會為每個CPU core設置一個固定周期的時鐘中斷,這個中斷是一個很重要的搶占的時機,時鐘中斷處理程序會判斷下面需要讓哪個進程搶到CPU。一個處在用戶態的進程執行一段時間后,時鐘中斷觸發,進程調度算法(例如:CFS)可能就會將CPU分配給其他進程,從而不會讓這個進程一直占用CPU。而一個處在內核態的進程則不同,首先它可以屏蔽中斷響應,這就直接去除了搶占的時機,其次它也可以顯示的關閉搶占,同時如果是個內核進程,他的優先級高于普通進程并且調度策略也不同于CFS,以上這些情況下如果不主動讓出CPU,其他進程就無法獲取執行,最終就會導致問題出現。


上面描述的現象在linux里面稱為:軟鎖(soft_lockup)和硬鎖(hard_lockup)


  • soft_lockup

CPU被某個進程長時間占用,其他進程得不到調用。例如:長時間禁用內核搶占


  • soft_lockup告警打印

3.jpg


  • hard_lockup

CPU被某個進程長時間占用,其他進程得不到調用,同時也不響應中斷。例如:長時間屏蔽中斷響應


  • hard_lockup告警打印

4.jpg



■機制


?Linux內核通過watchdog機制來檢查系統中是否出現soft_lockup和hard_lockup。watchdog的主要思想是:通過優先級更高的任務來觀察優先級較低的任務(進程/中斷)是否被成功執行調度,因此可以通過中斷來觀察進程是否被正常調度,而通過NMI(不可屏蔽中斷)來觀察中斷是否被響應。 


??我們可以通過如下內核參數來配置檢查條件和是否觸發panic,以幫助問題的后續分析。


# 開啟watchdog
kernel.watchdog = 1
# hardlockup超時時間,softlockup超時時間=2*watchdog_thresh
kernel.watchdog_thresh = 10
# 是否觸發panic
kernel.hardlockup_panic = 1
kernel.softlockup_panic = 1



■實現


??watchdog對應的代碼在watchdog.c中,主要實現邏輯:


  1. 為每個CPU core創建一個(watchdog/%u)內核進程,它會周期性的更新watchdog_touch_ts變量

  2. 設置一個時鐘中斷,它會周期性的更新hrtimer_interrupts變量 
    同時負責檢測soft_lockup,通過查看watchdog_touch_ts的值是否被更新,來判斷(watchdog/%u)進程是否被執行,從而判斷CPU是否被其他進程一直占用

  3. 設置一個NMI(不可屏蔽中斷),它會每watchdog_thresh秒觸發一次 
    同時負責檢測hard_lockup,通過查看hrtimer_interrupts的值是否被更新,來判斷是否出現hard_lockup


對應內核代碼


#watchdog.c
static int watchdog_enable_all_cpus(void)
{
 ... ...
   if (!watchdog_running) {
       err = smpboot_register_percpu_thread(&watchdog_threads);    //創建(watchdog/%u)內核進程
   ... ...
}

static void __touch_watchdog(void)
{
   __this_cpu_write(watchdog_touch_ts, get_timestamp());        //更新watchdog_touch_ts
}

static void watchdog_enable(unsigned int cpu)
{
   ... ...
   hrtimer->function = watchdog_timer_fn;    //設置時鐘中斷
 watchdog_nmi_enable(cpu);        //設置NMI(非屏蔽中斷)
   hrtimer_start(hrtimer, ns_to_ktime(sample_period), HRTIMER_MODE_REL_PINNED);    //啟動時鐘中斷

}

static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
{
   ... ...
   watchdog_interrupt_count();        //更新hrtimer_interrupts

   wake_up_process(__this_cpu_read(softlockup_watchdog));

   ... ...
   duration = is_softlockup(touch_ts);        //檢查softlockup
 ... ...
}

static bool is_hardlockup(void)    //檢查hardlockup
{
   unsigned long hrint = __this_cpu_read(hrtimer_interrupts);

   if (__this_cpu_read(hrtimer_interrupts_saved) == hrint)
       return true;

   __this_cpu_write(hrtimer_interrupts_saved, hrint);
   return false;
}



總結


以上介紹了三種最常見的導致進程或系統hung住的場景和相關的背景及原理。在遇到這些情況的時候我們可以更快速的判斷出現問題的基本原因和可能的地方。同時也介紹了linux內核提供的一些機制,幫助我們檢查并收集必要的日志和信息。有了這些信息,我們就可以通過分析日志、利用kdump等工具來進一步排查問題的最終原因。


上述代碼源自Redhat-7.5,kernel版本:linux-3.10.0-862.el7




讓數據庫基礎設施更簡單
加速企業數字化轉型建設及落地
立即咨詢

沃趣科技

中立的企業級數據庫云
十年磨一劍十年來始終如一的專注數據庫生態領域
夯實技術底蘊打造最適合時代的數據庫基礎設施
業績持續領先目前已累計服務超3000家企業客戶

留言咨詢

完善信息,我們第一時間跟您聯系
姓名
手機
公司
所在地區
咨詢問題