God教程

韓師學子--胖佳發表於2019-03-24

                   God教程


轉載:https://www.jianshu.com/p/c948585ef41e
 

一、什麼是God

God 是用 Ruby 寫的程式監控框架,具有易配置易擴充套件的優點。用它可以很方便的監控一個軟體的執行狀態,並在特定的條件下殺死或重啟程式,以保證任務的永續性和高可用性。

常見場景

  • 監控一個程式,當它因意味錯誤退出或失去響應時重新啟動它。
  • 監控一個程式,當它耗費的CPU或記憶體超過特定值時殺死或重新啟動它。

二、God的優缺點

優點:

  • 啟動和控制都使用一個命令: god
  • 可以管理daemon和非daemon程式
  • 可以設定程式的uid、env、dir、log等引數
  • 程式配置檔案和supervisord類似,但使用ruby的語法。支援類似monit的,對程式使用資源和各種條件的控制
  • 支援程式配置動態載入功能
  • 支援把多個程式配置拆分成單獨的配置檔案,類似include功能
  • 支援通知功能,包括:Webhook、Email、Twitter、Jabber、Campfire等多個介面
  • 根據PID的方式進行監控,GOD可以隨便升級和重啟

缺點

  • 不提供web端和rpc介面
  • log檢視stdrr/stdout 功能似乎不能正常work,不過我基本上用不到這個功能
  • linux下采用2種方式檢測程式poll和event。root預設啟用event模式,如果啟動的程式錯誤,它會註冊一個proc_exit事件,但無法響應。

三、安裝

最好的方法是通過rubygems安裝:

 $[sudo] gem install god

四、快速開始

新建一個目錄,然後寫一個簡單的伺服器指令碼。讓我們給它命名為simple.rb:

loop do
  puts 'Hello'
  sleep 1
end

現在我們將寫一個god配置檔案,告訴god關於我們的程式。把它和simple.rb放在同一個資料夾,命名為simple.god:

God.watch do |w|
  w.name = "simple"
  w.start = "ruby /full/path/to/simple.rb"
  w.keepalive
end

這是最簡單的god配置檔案。
我們以宣佈一個God.watch塊開始。
一個watch在god裡代表一個我們想要watch和控制的程式。
每個watch必須有一個唯一的名字和一個告訴god怎麼啟動程式的命令。
keepalive的宣告告訴god保持這個程式alive。
假如god啟動時這個程式沒有執行,god將會啟動它。假如程式不響應,god就會重新啟動它。

在這個例子裡,simple程式在前端執行,所以god會照看該程式,保持跟蹤這個程式的PID。
如果可能,最好要god為我們啟動程式,這樣我們就不必擔心指定和保持跟蹤PID的檔案。
後面我們將看見不能在前景執行或者需要指定程式PID的情況下怎樣管理。

為了執行god,我們使用引數-c給它提供一個引數。通過引數-D就可以讓god在前端執行,能讓我們看見發生了什麼。

$ god -c path/to/simple.god -D

god可以通過兩種方式來監控你的程式。
第一個和最好的一個是方法是用event。
不是每個系統都支援,但是如果系統支援的話會自動使用event。
通過event,god會立即知道一個程式是否存在。
對那些系統沒有event支援的,god使用polling機制。這個部分的整個輸出如下:

# Events
I [2011-12-10 15:24:34]  INFO: Loading simple.god
I [2011-12-10 15:24:34]  INFO: Syslog enabled.
I [2011-12-10 15:24:34]  INFO: Using pid file directory: /Users/tom/.god/pids
I [2011-12-10 15:24:34]  INFO: Started on drbunix:///tmp/god.17165.sock
I [2011-12-10 15:24:34]  INFO: simple move 'unmonitored' to 'init'
I [2011-12-10 15:24:34]  INFO: simple moved 'unmonitored' to 'init'
I [2011-12-10 15:24:34]  INFO: simple [trigger] process is not running (ProcessRunning)
I [2011-12-10 15:24:34]  INFO: simple move 'init' to 'start'
I [2011-12-10 15:24:34]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-10 15:24:34]  INFO: simple moved 'init' to 'start'
I [2011-12-10 15:24:34]  INFO: simple [trigger] process is running (ProcessRunning)
I [2011-12-10 15:24:34]  INFO: simple move 'start' to 'up'
I [2011-12-10 15:24:34]  INFO: simple registered 'proc_exit' event for pid 23298
I [2011-12-10 15:24:34]  INFO: simple moved 'start' to 'up'

# Polls

I [2011-12-07 09:40:18]  INFO: Loading simple.god
I [2011-12-07 09:40:18]  INFO: Syslog enabled.
I [2011-12-07 09:40:18]  INFO: Using pid file directory: /Users/tom/.god/pids
I [2011-12-07 09:40:18]  INFO: Started on drbunix:///tmp/god.17165.sock
I [2011-12-07 09:40:18]  INFO: simple move 'unmonitored' to 'up'
I [2011-12-07 09:40:18]  INFO: simple moved 'unmonitored' to 'up'
I [2011-12-07 09:40:18]  INFO: simple [trigger] process is not running (ProcessRunning)
I [2011-12-07 09:40:18]  INFO: simple move 'up' to 'start'
I [2011-12-07 09:40:18]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-07 09:40:19]  INFO: simple moved 'up' to 'up'
I [2011-12-07 09:40:19]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:40:24]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:40:29]  INFO: simple [ok] process is running (ProcessRunning)

你可以看見god啟動了,注意到simple沒有在執行,啟動它,然後每隔5分鐘檢查一下確保simple執行正常。
假如你想看見god的魔力,kill simple的程式。你會發現類似如下的輸出:

# Events
I [2011-12-10 15:33:38]  INFO: simple [trigger] process 23416 exited (ProcessExits)
I [2011-12-10 15:33:38]  INFO: simple move 'up' to 'start'
I [2011-12-10 15:33:38]  INFO: simple deregistered 'proc_exit' event for pid 23416
I [2011-12-10 15:33:38]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-10 15:33:38]  INFO: simple moved 'up' to 'start'
I [2011-12-10 15:33:38]  INFO: simple [trigger] process is running (ProcessRunning)
I [2011-12-10 15:33:38]  INFO: simple move 'start' to 'up'
I [2011-12-10 15:33:38]  INFO: simple registered 'proc_exit' event for pid 23601
I [2011-12-10 15:33:38]  INFO: simple moved 'start' to 'up'

# Polls

I [2011-12-07 09:54:59]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:55:04]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:55:09]  INFO: simple [trigger] process is not running (ProcessRunning)
I [2011-12-07 09:55:09]  INFO: simple move 'up' to 'start'
I [2011-12-07 09:55:09]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-07 09:55:09]  INFO: simple moved 'up' to 'up'
I [2011-12-07 09:55:09]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 09:55:14]  INFO: simple [ok] process is running (ProcessRunning)

保持程式啟動是好的,但是假如能夠保證我們的程式表現良好,當資源超過我們的設定,重新啟動程式將更好。通過新增一點條件,當記憶體或者CPU超過我們設定的限制,我們能夠容易地讓我們的程式重啟。編輯simple.god配置檔案如下:

God.watch do |w|
  w.name = 'simple'
  w.start = "ruby /full/path/to/simple.rb"
  w.keepalive( :memory_max => 150.megabytes,
               :cpu_max => 50.percent)
end

這裡我在keepalive命令中使用了 :memory_max 選項。
現在,假如程式的記憶體用量超過150M, god就會重啟他。
相似地,通過設定 :cpu_max, 假如CPU的使用超過50%,god也會重啟它。
預設這些屬性每隔30秒檢查一次,假如五個條件中滿足三個,則會執行。這防止了程式因為暫時的資源峰值導致重啟。

為了測試這個特性,修改你的simple.rb伺服器指令碼使得引起記憶體洩露:

data = ''
loop do
  puts 'Hello'
  100000.times { data << 'x' }
end

按Ctrl-C結束god。注意到你的simple程式依然在執行。
用剛才的方式再次啟動god。
現在代替了啟動simple程式,god監測到simple執行,簡單的切換到up狀態。

# Events
I [2011-12-10 15:36:00]  INFO: Loading simple.god
I [2011-12-10 15:36:00]  INFO: Syslog enabled.
I [2011-12-10 15:36:00]  INFO: Using pid file directory: /Users/tom/.god/pids
I [2011-12-10 15:36:00]  INFO: Started on drbunix:///tmp/god.17165.sock
I [2011-12-10 15:36:00]  INFO: simple move 'unmonitored' to 'init'
I [2011-12-10 15:36:00]  INFO: simple moved 'unmonitored' to 'init'
I [2011-12-10 15:36:00]  INFO: simple [trigger] process is running (ProcessRunning)
I [2011-12-10 15:36:00]  INFO: simple move 'init' to 'up'
I [2011-12-10 15:36:00]  INFO: simple registered 'proc_exit' event for pid 23601
I [2011-12-10 15:36:00]  INFO: simple moved 'init' to 'up'

# Polls

I [2011-12-07 14:50:46]  INFO: Loading simple.god
I [2011-12-07 14:50:46]  INFO: Syslog enabled.
I [2011-12-07 14:50:46]  INFO: Using pid file directory: /Users/tom/.god/pids
I [2011-12-07 14:50:47]  INFO: Started on drbunix:///tmp/god.17165.sock
I [2011-12-07 14:50:47]  INFO: simple move 'unmonitored' to 'up'
I [2011-12-07 14:50:47]  INFO: simple moved 'unmonitored' to 'up'
I [2011-12-07 14:50:47]  INFO: simple [ok] process is running (ProcessRunning)

為了讓我們的simple服務執行,我們重新啟動simple,這裡必須強烈地要求重啟否則新新增的配置不會生效

god restart simple 

通過日誌你可以看見god結束了simple程式並重新啟動了:

# Events

I [2011-12-10 15:38:13]  INFO: simple move 'up' to 'restart'
I [2011-12-10 15:38:13]  INFO: simple deregistered 'proc_exit' event for pid 23601
I [2011-12-10 15:38:13]  INFO: simple stop: default lambda killer
I [2011-12-10 15:38:13]  INFO: simple sent SIGTERM
I [2011-12-10 15:38:14]  INFO: simple process stopped
I [2011-12-10 15:38:14]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-10 15:38:14]  INFO: simple moved 'up' to 'restart'
I [2011-12-10 15:38:14]  INFO: simple [trigger] process is running (ProcessRunning)
I [2011-12-10 15:38:14]  INFO: simple move 'restart' to 'up'
I [2011-12-10 15:38:14]  INFO: simple registered 'proc_exit' event for pid 23707
I [2011-12-10 15:38:14]  INFO: simple moved 'restart' to 'up'

# Polls

I [2011-12-07 14:51:13]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:51:13]  INFO: simple move 'up' to 'restart'
I [2011-12-07 14:51:13]  INFO: simple stop: default lambda killer
I [2011-12-07 14:51:13]  INFO: simple sent SIGTERM
I [2011-12-07 14:51:14]  INFO: simple process stopped
I [2011-12-07 14:51:14]  INFO: simple start: ruby /Users/tom/dev/mojombo/god/simple.rb
I [2011-12-07 14:51:14]  INFO: simple moved 'up' to 'up'
I [2011-12-07 14:51:14]  INFO: simple [ok] process is running (ProcessRunning)

God現在開始報告記憶體和CPU的使用情況

# Events and Polls

I [2011-12-07 14:54:37]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:54:37]  INFO: simple [ok] memory within bounds [2032kb] (MemoryUsage)
I [2011-12-07 14:54:37]  INFO: simple [ok] cpu within bounds [0.0%%] (CpuUsage)
I [2011-12-07 14:54:42]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:54:42]  INFO: simple [ok] memory within bounds [2032kb, 13492kb] (MemoryUsage)
I [2011-12-07 14:54:42]  INFO: simple [ok] cpu within bounds [0.0%%, *99.7%%] (CpuUsage)
I [2011-12-07 14:54:47]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:54:47]  INFO: simple [ok] memory within bounds [2032kb, 13492kb, 25568kb] (MemoryUsage)
I [2011-12-07 14:54:47]  INFO: simple [ok] cpu within bounds [0.0%%, *99.7%%, *100.0%%] (CpuUsage)
I [2011-12-07 14:54:52]  INFO: simple [ok] process is running (ProcessRunning)
I [2011-12-07 14:54:52]  INFO: simple [ok] memory within bounds [2032kb, 13492kb, 25568kb, 37556kb] (MemoryUsage)
I [2011-12-07 14:54:52]  INFO: simple [trigger] cpu out of bounds [0.0%%, *99.7%%, *100.0%%, *98.4%%] (CpuUsage)
I [2011-12-07 14:54:52]  INFO: simple move 'up' to 'restart

在最後的一行,你能看見CPU的用量已經超過了50%三次了,
god重新啟動了程式。god會持續地監測simple程式,只要god在執行,程式就會被一直監控。

現在,你結束god之前,讓我們先通過god結束simple服務。在一個新的終端,輸入以下命令:

god stop simple 

如果想停止god,你可以自由地Ctrl-C 退出god 了。

不過這只是個開始。在實際應用中,keepalive 命令是一個方便的方法,使用了可以直接使用的更高階的事務和條件構造。你可以配置許多不同的條件,當CPU或者記憶體使用太多,磁碟超過下限,當一個指定的URL返回錯誤程式碼,等等。另外,你可以寫自己的自定義條件,然後在配置檔案裡使用它。伴隨著複雜的和可擴充套件的通知體系,可以控制許多不同的生命週期。

既然你已經知道怎麼使用god,讓我們看看god更強大的一面吧。再說一次,最好的學習方法是通過示例。下面這個配置檔案是我在gravatar.com保證mongrels執行使用的配置檔案。

## 在這裡我設定了一個常量,用於整個檔案。保持RAILS_ROOT的值是一個常量使得指令碼很容易適合其他應用
RAILS_ROOT = "/Users/tom/dev/gravatar2"


## 迴圈監控  8200 8210 8202 埠
%w{8200 8201 8202}.each do |port|
  God.watch do |w|
    w.name = "gravatar2-mongrel-#{port}"

    ## 使用 mogrel_rails 命令啟動
    w.start = "mogrel_rails start -c #{RAILS_ROOT} -p #{port} \
      -P #{RAILS_ROOT}/log.mogrel.#{port}.pid -d"

    ## 使用 mogrel_rails 命令停止
    w.stop = "morgrel_rails stop -P #{RAILS_ROOT}/log/mogrel.#{port}.pid"
    ##  重啟
    w.restart = "mongrel_rails restart -P #{RAILS_ROOT}/log/mogrel.#{port}.pid"

    w.pid_file = File.join(RAILS_ROOT, "log/mogrel.#{port}.pid")

    ## 假如你正監視的程式是一個後天程式(我的也是),你需要設定pid_file屬性。????
    ## behavio允許你伴隨著start/stop/restart執行額外的命令。
    ## 在我們的例子裡,假如程式死了,它會留下PID檔案。
    ## 假如下次重新啟動這個程式,就會啟動失敗,提示PID檔案已經存在。
    ## 所以啟動程式時,我們想先清除PID檔案。內建的clean_pid_file就會清除
    w.behavior(:clean_pid_file)


    ## watch包含由可執行的動作組成的條件應該返回true
    w.start_if do |start|
      start.condition(:process_running) do |c|
        ## 通過用一個識別字元呼叫condition條件來描述condition,這個例子中是:process_running. 每個條件描述一個poll間隔,這個間隔將覆蓋預設的間隔。這個例子中,我想要每個5秒鐘檢查一次程式,而不是像其他condition一樣用30秒間隔
        c.inteval = 5.seconds
        c.running = false
      end
    end

    ## 和start_if類似,restart_if命令組合condition,
    ## 然後觸發restart。memory_usage條件將會失敗,
    ## 假如指定的程式使用了太多的記憶體。
    ## 最大允許的記憶體通過above屬性來指定(你可以用kilobytes, megabytes, 或者gibabytes助手)。
    ## 為了觸發restart需要觸發的次數通過times設定。
    ## 這個可以是一個整數,也可以是一個陣列。
    ## 整數意味著它必須連續失敗許多次而陣列[x, y]意味著必須y次中失敗x次。
    w.restart_if do |restart|
      restart.condition(:memory_usage) do |c|
       c.above = 150.megabytes
       c.times = [3, 5] # 3 out of 5 intevals
      end

      restart.condition(:cpu_usage) do |c|
        c.above = 50.percent
        c.times = 5
      end
    end

    #lifecycle
    ## 在lifecycle部分中的condition只要程式被監視就一直活動(它們通過狀態的改變活動)。
    ## :flapping condition守護除了god快速開始和重啟你的應用的這些邊緣的狀態的其他情況。
    ## 比如伺服器配置變化或者外部服務的不可用都可能造成我得程式不能啟動。
    ## 那樣的話,god將會一直重試啟動我的程式。
    ## :flapping condition提供了兩個水平的放棄不穩定程式。
    ## 假如我翻譯以上的option程式碼,那就是:
    ## 假如watch在5分鐘裡被啟動或者重啟了5次,然後不再監視它。。。
    ## 然後10分鐘後,再次監視他看看是否只是一個臨時的問題;
    ## 假如程式在兩小時裡依然不穩定,然後徹底放棄監視
    ## lifecycle 是一個非常重要的配置,之前聽過架構師說過,God 程式怎麼一直在重啟
    ## 肯定就是這裡的坑!!!!!!!
    w.lifecycle do |on|
     on.condition(:flapping) do |c|
       c.to_state = [:start, :restart]
       c.times = 5
       c.within = 5.minute
       c.transition = :unmonitored
       c.retry_in = 10.minutes
       c.retry_times = 5
       c.retry_within = 2.hours
     end
    end
   end
  end

五、動態載入檔案進入一個已經執行的god

God允許你載入或者重新載入配置檔案進入一個已經執行的例項。當你準備這樣做得時候,有幾件事情需要考慮:

  • 已經存在的watch會被新配置檔案裡的同名的watch覆蓋
  • 所有的路徑必須是絕對路徑或者god執行的相對路徑

將配置檔案載入至一個正在執行的god,執行以下命令:

sudo god load path/to/config.god

動態載入的配置檔案可以包含任何一個普通的配置檔案,然而,全域性變數例如God.pid_file_directory塊將可能會被忽視(會在日誌裡產生一個警告)。

如果把god作為一個後臺程式,只需要把配置檔案的路徑傳遞給god(你需要使用sudo假如你在linux使用event或者想要使用setuid/setgid)

sudo god -c /path/to/config.god

當你寫配置檔案的時候,在前臺執行god這樣你能看見log訊息,可能會很有幫助。你可以:

sudo god -c /path/to/config.god -D

你能啟動、重啟、停止、監測、不監測你的watch用同樣的工具像這樣:

sudo god stop gravatar2-mongrel-8200

六、God 的其他功能

+ 重定向你程式的STDOUT和STDERR
+ 改變程式的UID/GID
+ 設定工作目錄
+ 設定環境變數
+ 使用CHROOT改變檔案系統的根目錄
+ Lambda命令
+ 自定義預設的停止執行lambda
+ 載入其他配置檔案
+ 為單個watch得到日誌檔案