Kubernetes中CronJob源码阅读
Contents
遇到的问题
上期博客中, 已经讲到了suspend参数带来的一个问题:
如果你将
suspend
由true
变更为false
时, 也就是重新打开定时任务, 错过的任务会立刻执行(如果没有设置 starting deadline), K8S会马上调度先前错过的任务.
另外还有可能遇到这样报错:
too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew 太多的任务丢失了(超过100), 1. 设置或是减少
.spec.startingDeadlineSeconds
, 2. 检查时钟偏移
startingdeadlineseconds含义 – 官方文档
官方文档中是这样给出的:
1 | The .spec.startingDeadlineSeconds field is optional. It stands for the deadline in seconds for starting the job if it misses its scheduled time for any reason. After the deadline, the cron job does not start the job. Jobs that do not meet their deadline in this way count as failed jobs. If this field is not specified, the jobs have no deadline. |
官方文档-CronJob的限制中更加详细:
增量的部分是:
1 | A CronJob is counted as missed if it has failed to be created at its scheduled time. For example, If concurrencyPolicy is set to Forbid and a CronJob was attempted to be scheduled when there was a previous schedule still running, then it would count as missed. |
如果你看了上面的内容已经明白了
suspend
以及startingDeadlineSeconds
的用法, 那自然是极好的, 如果仍然觉得云里雾里, 那之后请随我一起去看K8S中此部分的源码.
K8S中的cronjob代码阅读:
我会以Kubernetes v1.17的代码为例, 以下代码截取自, 我将error处理的部分已全部删掉:
https://github.com/kubernetes/kubernetes/blob/v1.17.0/pkg/controller/cronjob/cronjob_controller.go
1 | // Run starts the main goroutine responsible for watching and syncing jobs. |
总结
阅读了Kubernetes的Cron任务实现后, 基本对其实现有了大体的把握.
重要的一点是K8S每10s检查一次定时任务的时间点,
检查 当前时间 - DeadlineSeconds
<=> 当前时间
中未被调度的任务时间点,
选择最后一项任务进行执行, 并更新该任务的调度时间.
FAQ
下面的讨论均是建立在定时任务的最小粒度为分钟!!!
在Linux的cron任务中,
* * * * *
表示每分钟执行一次.
任务是否会完全不执行
有可能, 有下面两种情况
- 不设置DeadlineSeconds, 或是DeadlineSeconds过大, 导致missed任务超过100个, K8S将不会执行此定时任务
- 当你的DeadlineSeconds设置为10s以内, 每次的
now - DeadlineSeconds
可能都不会包含任务的执行点
任务是否会多执行或是少执行
有可能, 不过最多只会多执行一次. K8S会在下一次该任务调度时执行. 下面是这种场景:
以最小粒度每分钟为例, 1分钟 >> 10s, 假如其中有一次任务执行花费了2分22秒
1 | start end |
我们会在2分30秒的时候触发检查, 如果DeadlineSeconds>30s, 那么2分钟这个点会被包含在K8S所调度的任务中, 本来已经被忽略的任务执行了一次.
从上面这个例子也能看出, K8S的定时任务不会少执行任务的.
DeadlineSeconds该设置多大?
目前来看, Deadline设置小于6000s, 大于10s这个区间就可以. 我倾向于将这个时间取小, 10分钟(600)以内.
应该应对的异常
- 上述例子中, 任务的实际执行时长大于任务间隔. 本来应该每分钟执行的定时任务, 但由于某次任务执行时间较长, 导致区间的部分任务丢失.
len(times) > 1
说明任务有积存, 需要我们确认系统状况.