Monitoring

monit:如何在不使伺服器超載的情況下重新啟動許多 Tomcat?

  • September 17, 2015

我的伺服器有幾個單獨的 Apache Tomcat 實例,每個實例都需要大量時間和 CPU 才能啟動。不可能同時啟動所有這些。這會產生過多的 I/O,每個服務將需要更長的時間才能啟動,並且服務甚至可能由於內部超時而無法啟動。

這是一些描述我想要做的虛擬碼。我將如何使用 monitrc 文件完成此操作?

check process service01 with pidfile /var/run/service01.pid
   start program = "/usr/sbin/service service01 start" with timeout 60 seconds
   stop program  = "/usr/sbin/service service01 stop"
   if does not exist then
       wait a random number of seconds (between 2 and 5 minutes)
       if the cpu load is < 100% then
           start program
       else 
           do nothing (check again in the next cycle)

check process service02 with pidfile /var/run/service02.pid
....

將為 10 個服務中的每一個重複此程式碼塊。

關鍵步驟是隨機等待。否則,如果伺服器空閒並且沒有服務在執行(例如在 ‘killall -9 java’ 之後),monit 將檢查所有服務,發現 cpu 負載現在很低,並立即啟動所有服務。

我現在已經找到了可以完成這項工作的設置。重啟或多個程序失敗後,檢查CPU負載,每個服務只有在CPU負載低於1或延遲較長時間後才會啟動。下面的腳本在我的環境中工作得很好:

編輯/etc/monitor/monitorrc:

...
## Start Monit in the background (run as a daemon):
#
set daemon 120              # check services at 2-minute intervals
   with start delay 240    # optional: delay the first check by 4-minutes (by
#                           # default Monit check immediately after Monit start)

對於每個服務,將其添加到 /etc/monit/conf.d:

check process myname with pidfile /var/run/app0000.pid
   start program = "/usr/sbin/service app0000 start" with timeout 60 seconds
   stop program  = "/usr/sbin/service app0000 stop"
   if does not exist then exec "/root/bin/service_with_delay app0000 start"

創建腳本 /root/bin/service_with_delay:

#!/bin/bash
(
 # Wait for lock on /var/lock/service_with_delay.lock (fd 9)
 flock -n 9 || exit 1

 for i in `seq 1 10`; do

   # start the service if the cpu load is < 1.0 or after waiting for 300 seconds

   read load ignore </proc/loadavg
   flag=`expr ${load} '<' 1`
   if [ ${flag} -eq 1 ] || [ ${i} -eq 10 ]; then

       echo `date` service_with_delay $1: pid $$ load ${load} i ${i} - starting >> /var/log/service_with_delay.log
       /usr/sbin/service $1 start

       # make sure next script getting the lock sees some load
       sleep 60
       break
   fi

   # wait
   echo `date` service_with_delay $1: pid $$ load ${load} i ${i} >> /var/log/service_with_delay.log
   sleep 30
 done
) 9> /var/lock/service_with_delay.lock

您沒有過多介紹您的作業系統,我只能假設它是 Linux(kill -9 ...部分)。我對monit也不太了解,但假設它是一個靈活的解決方案,允許您在服務失敗時重試啟動服務。

我假設 Tomcat 實例是使用 shell 啟動腳本啟動的。在這些腳本的開頭添加某處:

# edit the 3 lines to set your limits
LOAD_THRESHOLD=0.75
LOCK_TIME=30
TIME_LIMIT=120

LOCK_FILE='/var/lock/tomcat-delay.lock'

if [ -z "${TOMCAT_NOLOCK}" ]; then
   # simple locking mechanism to avoid simultaneous start of instances
   if [ -f "${LOCK_FILE}" ] && [ $(cat "${LOCK_FILE}") -gt $(date '+%s') ]; then
       exit 1
   else
       expr $(date '+%s') + ${LOCK_TIME} 1>"${LOCK_FILE}"
   fi
fi

T_TIME=0
while true; do
   # check for non-empty TOMCAT_NOWAIT
   if [ -n "${TOMCAT_NOWAIT}" ]; then
       break 1
   fi
   read T_LOAD60 T_REST </proc/loadavg
   # check current 60 sec. average value for system load
   if expr ${T_LOAD60} '<' ${LOAD_THRESHOLD} 1>/dev/null; then
       break 1
   fi
   # check for timeout
   if [ ${T_TIME} -ge ${TIME_LIMIT} ]; then
       # change to 'exit 1' to fail on timeout instead of proceeding
       break 1
   fi
   sleep 1s
   echo -n '.'
   T_TIME=$((${T_TIME} + 1))
done

上面的程式碼實際上並不僅僅檢查 CPU 負載,而是檢查系統負載平均值,根據設計,它包括所有可能降低性能的因素。TIME_LIMIT以秒為單位。如果負載在給定時間內未低於給定門檻值,腳本將最終嘗試啟動您的服務 - 最後break 1一部分可以更改為exit 1以中止啟動並告訴monit守護程序重試。

如果您嘗試手動啟動服務(而不是從monit),它也會等待,我認為這是一個優勢。您可以使用非空值導出 env TOMCAT_NOWAIT以避免它。

**編輯#1:**添加簡單的鎖定機製作為同時實例啟動問題的解決方法。非空環境 TOMCAT_NOLOCK禁用鎖定。將LOCK_TIME 設置為實例的預熱時間,以便正確檢測到高負載。

引用自:https://serverfault.com/questions/710142