为什么在kubernetes cron job中可能会创建两个作业,或者可能没有创建作业?

rad*_*tao 15 cron jobs distributed-computing kubernetes

在k8s中,Cron Job Limitations提到无法保证作业只执行一次:

cron作业在其计划的每个执行时间创建一个作业对象.我们说"约",因为在某些情况下可能会创建两个作业,或者不会创建任何作业.我们试图使这些罕见,但不要完全阻止它们.因此,工作应该是幂等的

谁能解释一下:

  • 为什么会这样?
  • 这可能发生的概率/统计数据是什么?
  • 它将在k8s的某个合理的未来被修复吗?
  • 是否有任何变通办法来防止这种行为(如果正在运行的作业不能实现为幂等)?
  • 其他与cron相关的服务遭遇同样的问题吗?也许这是一个核心的cron问题?

Jon*_*ton 8

控制器:

https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/cronjob/cronjob_controller.go

从评论开始,为解释奠定基础:

I did not use watch or expectations. Those add a lot of corner cases, and we aren't expecting a large volume of jobs or scheduledJobs. (We are favoring correctness over scalability.)  

If we find a single controller thread is too slow because there are a lot of Jobs or CronJobs, we we can parallelize by Namespace. If we find the load on the API server is too high, we can use a watch and UndeltaStore.) 

Just periodically list jobs and SJs, and then reconcile them.
Run Code Online (Sandbox Code Playgroud)

每10秒定期一次:

https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/cronjob/cronjob_controller.go#L105

引用限制之后的文档在某些情况下也有一些有用的颜色,在这些情况下,可能会按特定计划启动2个作业或无作业:

If startingDeadlineSeconds is set to a large value or left unset (the default) and if concurrentPolicy is set to AllowConcurrent, the jobs will always run at least once.

Jobs may fail to run if the CronJob controller is not running or broken for a span of time from before the start time of the CronJob to start time plus startingDeadlineSeconds, or if the span covers multiple start times and concurrencyPolicy does not allow concurrency. For example, suppose a cron job is set to start at exactly 08:30:00 and its startingDeadlineSeconds is set to 10, if the CronJob controller happens to be down from 08:29:00 to 08:42:00, the job will not start. Set a longer startingDeadlineSeconds if starting later is better than not starting at all.
Run Code Online (Sandbox Code Playgroud)

更高级别,在分布式系统中只解决一次很难:

https://bravenewgeek.com/you-cannot-have-exactly-once-delivery/

分布式系统中的时钟和时间同步也很困难:

https://8thlight.com/blog/rylan-dirksen/2013/10/04/synchronization-in-a-distributed-system.html

对于问题:

  • 为什么会这样?

    例如,托管CronJobController的节点在作业应该运行时失败.

  • 这可能发生的概率/统计数据是什么?

    任何给定的运行都不太可能.对于足够多的运行,不太可能逃避不得不面对这个问题.

  • 它将在k8s的某个合理的未来被修复吗?

    在k8s回购中的区域/批次标签下没有与标准能力有关的问题,所以人们不会猜测.

    https://github.com/kubernetes/kubernetes/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2Fbatch

  • 是否有任何变通办法来防止这种行为(如果正在运行的作业不能实现为幂等)?

    更多地考虑幂等的具体定义,以及有提交的工作中的特定点.例如,如果将状态保存到暂存区域,则可以使作业支持多次执行,然后有一个选举过程来确定谁的工作获胜.

  • 其他与cron相关的服务遭遇同样的问题吗?也许这是一个核心的cron问题?

    是的,这是核心分布式系统问题.

    对于大多数用户而言,k8s文档可能提供了比必要更精确和细致的答案.如果您的预定工作正在控制某些关键的医疗程序,那么计划失败案例非常重要.如果只是进行一些系统清理,那么错过预定的运行并不重要.根据定义,几乎所有k8s CronJobs的用户都属于后一类.

  • 看起来很清楚,很多.至于"当工作控制器失败时工作可能没有开始" - 这是非常明显的,虽然为什么它可以开始倍增时间更难理解. (3认同)
  • 我一直在一个 cron 执行点运行多个作业。但似乎只有这些作业的运行时间很短。知道为什么会发生这种情况以及如何预防吗?我使用 concurrencyPolicy: Forbid, backoffLimit: 0 和 restartPolicy: Never。 (2认同)
  • 与此同时,源代码已移至 https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/cronjob/cronjob_controllerv2.go。该评论不再存在。但文档仍然提到“几乎”一次警告。很少有作业不运行的情况。很少有作业运行两次。https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/ (2认同)