有效地分发 cron 任务
当你有许多服务器需要执行相同的 cron 作业时,不在同一时间运行它们通常是个好主意。 如果所有作业都要访问一个公共服务器,就会给该服务器带来大量负载, 即使这些服务器不会同时访问公共服务器,所有服务器也会在同一时间处于繁忙状态, 这可能会削减它们提供其他服务的能力。
Puppet 的 inline_template 函数允许我们使用 Ruby 的逻辑根据主机名为 cron 作业设置不同的运行时间。
操作步骤
在一个节点中添加如下代码:
define cron_random( $command, $hour ) { cron { $name: command => $command, minute => inline_template("<%= (hostname+name).hash.abs %60 %>"), hour => $hour, ensure => "present", } } cron_random { "hello-world": command => "/bin/echo 'Hello world'", hour => 2, } cron_random { "hello-world-2": command => "/bin/echo 'Hello world'", hour => 1, }
运行 Puppet:
# puppet agent --test info: Retrieving plugin info: Caching catalog for cookbook.bitfieldconsulting.com info: Applying configuration version '1305713506' notice: /Stage[main]//Node[cookbook]/Cron_random[hello-world]/ Cron[hello-world]/ensure: created notice: /Stage[main]//Node[cookbook]/Cron_random[hello-world-2]/ Cron[hello-world-2]/ensure: created notice: Finished catalog run in 1.07 seconds
检查 crontab 查看是否成功地配置了 cron 作业:
# crontab -l # HEADER: This file was autogenerated at Fri Jul 29 10:58:45 +0000 2011 by puppet. # HEADER: While it can still be managed manually, it is definitely not recommended. # HEADER: Note particularly that the comments starting with 'Puppet Name' should # HEADER: not be deleted, as doing so could cause duplicate cron jobs. # Puppet Name: hello-world 25 2 * * * /bin/echo 'Hello world' # Puppet Name: hello-world-2 49 1 * * * /bin/echo 'Hello world'
工作原理
我们想要为每个 cron 作业选择一个 随机的 执行分钟数; 而不是真正的随机 (或者说,不是每次运行 Puppet 都会改变 cron 作业的运行时间), 但这也或多或少地保证了每个主机上的每个 cron 作业运行时间的不同。
我们可以使用 Ruby 的 hash 方法实现它,它会对任何对象(本例为一个字符串)计算出一个哈希值。 尽管看上去这个哈希值是随机的,但它每次运行时都相同,所以当再次运行 Puppet 时其值不会改变。
哈希值生成的是一个大整数,而我们想要的是一个 0 到 59 之间的整数,所以我们使用了 Ruby 的 % (模)运算符将其结果限制在这个范围内。因为只有 60 种可能的值,尽管 hash 函数被设计为尽可能产生随机的输出,还是会有些许的碰撞而且这些碰撞对于 minute 应该是均匀分布的。
因为我们希望每个哈希值在不同的主机上是不同的,所以使用主机名做 hash 处理。 然而,我们还希望同一台主机上的不同作业的哈希值也不同,所以联合使用了主机名和作业名 (例如 hello-world)做 hash 处理。
更多用法
在本例中,我们仅对 cron 作业的 minute 进行了随机化,并将 hour 作为 define 定义的一部分。若你同时希望指定要在周几运行,可以在 cron_random 中添加一个附加参数来指定, 可以像下面这样为其指定默认值:
define cron_random( $command, $hour, $weekday = "*" ) {
若你想要对 cron 作业的 hour 进行随机化(例如:要做的作业可以在一天之内的任何时间执行, 并且必须将它们均匀分布在所有的 24 个小时上),可以对 cron_random 做如下修改:
hour => inline_template("<%= (hostname+name).hash.abs % 24 %>"),
参见本书
- 第 1 章的 从 cron 运行 Puppet 一节