天天看點

簡單的程序守護程式

項目突然上線了一個測試包,這個程式包老是會突然就死掉,雖然已經打回開發那邊改了,但是服務這邊又不允許回退版本,是以我隻能頂着個爛包來幹活了。zabbix那邊可以監控,但是很多時候我在外面,無法跑回去重新開機,是以打算寫一個簡單的程序守護程式來監控它

資産上有jdk,也有py和go環境,腳本類的程式的話就不用java寫了,python的版本比較低,我也沒有root權限去更新python版本,是以用python來完成這個腳本的話可能會遇到很多不相容的寫法,最後選擇了go來寫

我的思路是:啟動一個程式,每隔20秒列印一次該程序的pid和狀态到日志中,假如檢測不到該程序的pid,則重新啟動該程式。假如檢查到程序狀态為T或Z,就重新啟動該程式。假如檢測到程式日志檔案長時間大小沒有增加,則重新啟動(此步未完成,因為這個程式包的日志正常情況下不持續列印)

為了友善示範,我就随便開個tomcat,來模拟一個程序,先上代碼:

package main

import(
"fmt"
"os/exec"
"bytes"
"time"
"strings"
)


func main() {

for {
 
  var outInfo bytes.Buffer
  //用exec.Command來調用linux指令,這條linux指令如果被調用會列印出pid和狀态
  cmd := exec.Command("bash", "-c", "ps aux|grep tomcat|grep -v grep|awk '{print $2,$8}'")
  //接收輸出
  cmd.Stdout = &outInfo
  //執行指令
  cmd.Run()
  output := outInfo.String()
 
  //這裡加個時間,因為要列印到日志裡,沒有時間的話定位不到程式什麼時候斷了
  fmt.Print(time.Now().Format("2006-01-02 15:04:05"))
  
  //判斷接收到的輸出值是否為空
  if output=="" {
   //空的話說明程式沒有啟動,調用下面寫好的啟動函數
   startProcess()  
   
  }else if status:= strings.Contains(output,"T");status{
     
     reloadProcess()
    
   }else if status:= strings.Contains(output,"Z");status{

       reloadProcess()

    }else if status:= strings.Contains(output,"X");status{

        reloadProcess()

     }else{

         fmt.Println(":[INFO]tomcat程式存在!")
      }
   //由于是有執行操作的死循環,來個延時,這裡設定20秒
   time.Sleep(time.Duration(20)*time.Second)
   }
}

func startProcess(){
  var outInfo bytes.Buffer
  fmt.Println(":[ERROR]tomca未啟動,正在自動啟動中...")
  //這裡調用了啟動tomcat的指令
  cmd := exec.Command("bash", "-c", "sh apache-tomcat-8.5.79/bin/startup.sh")
  cmd.Stdout = &outInfo
  cmd.Run()
  fmt.Println(outInfo.String())
}

func reloadProcess(){
  var outInfo bytes.Buffer
  fmt.Println(":[ERROR]程序狀态異常!正在重新啟動...")
  //這裡調用了殺死程序和重新啟動的指令
  cmd_stop := exec.Command("bash", "-c", "ps aux|grep |awk '{print $2}'|xargs kill -9")
  cmd_start := exec.Command("bash", "-c", "sh apache-tomcat-8.5.79/bin/startup.sh")
  cmd_start.Stdout = &outInfo
  cmd_stop.Run()
  cmd_start.Run()
  fmt.Println(outInfo.String())
}

           

我将它寫成了一個test.go檔案,在終端執行

nohup go run test.go >> run.log 2>&1 &

簡單的程式守護程式

ps一下這個腳本檔案是否存在

ps aux|grep test.go

簡單的程式守護程式

可以看到腳本已經跑起來了,現在去日志看看

tail -f -n 100 run.log

簡單的程式守護程式

可以看到腳本一直在監控着tomcat,現在我們把tomcat程序殺掉,然後再看看情況:

簡單的程式守護程式

tomcat已經殺掉了,模拟程式停掉的情況,現在傳回日志看看情況:

簡單的程式守護程式

可以看到日志中檢測到tomcat停止,然後自動把它給啟動了,在ps一下看看tomcat是否已經啟動:

簡單的程式守護程式
簡單的程式守護程式

可以看到程序是在的,頁面也可以正常打開。

#!/bin/bash
log=/data/log/access.log
N=30 #設定門檻值

while true
do
#檢視通路日志的最新300條,并統計502的次數
err=`tail -n 300 $log |grep -c '502" '` 
#如果日志中出現502的次數大于我們設定的門檻值
if [ $err -ge $N ] 
then
/etc/init.d/php-fpm restart 2> /dev/null 
#設定60s延遲防止腳本bug導緻無限重新開機php-fpm服務
     sleep 60
 fi
 sleep 10
 done
           

繼續閱讀