目录
God 是用 Ruby 写的进程监控框架,具有易配置易扩展的优点。用它可以很方便的监控一个软件的运行状态,并在特定的条件下杀死或重启进程,以保证任务的持久性和高可用性。
常见场景
优点:
缺点
最好的方法是通过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,运行以下命令:
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
+ 重定向你进程的STDOUT和STDERR
+ 改变进程的UID/GID
+ 设置工作目录
+ 设置环境变量
+ 使用CHROOT改变文件系统的根目录
+ Lambda命令
+ 自定义默认的停止运行lambda
+ 加载其他配置文件
+ 为单个watch得到日志文件