QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

Kubernetes 中定时任务的实现

  • 2020-01-10
  • 本文字数:2073 字

    阅读完需:约 7 分钟

Kubernetes 中定时任务的实现

Kubernetes 中定时任务的实现

K8s 中有许多优秀的包都可以在平时的开发中借鉴与使用,比如,任务的定时轮询、高可用的实现、日志处理、缓存使用等都是独立的包,可以直接引用。


本文将介绍 K8s 中定时任务的实现,K8s 中定时任务都是通过 wait 包实现的。wait 包在 K8s 的多个组件中都有用到,以下是 wait 包在 kubelet 中的几处使用:


func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies, stopCh <-chan struct{}) (err error) {



// kubelet 每 5 分钟一次从 apiserver 获取证书


closeAllConns, err := kubeletcertificate.UpdateTransport(wait.NeverStop, clientConfig, clientCertificateManager, 5*time.Minute)


if err != nil {


return err


}


closeAllConns, err := kubeletcertificate.UpdateTransport(wait.NeverStop, clientConfig, clientCertificateManager, 5*time.Minute)


if err != nil {


return err


}



}



func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableServer bool) {


// 持续监听 pod 的变化


go wait.Until(func() {


k.Run(podCfg.Updates())


}, 0, wait.NeverStop)



}


golang 中可以通过 time.Ticker 实现定时任务的执行,但在 K8s 中用了更原生的方式,使用 time.Timer 实现的。time.Ticker 和 time.Timer 的使用区别如下:


  • ticker 只要定义完成,从此刻开始计时,不需要任何其他的操作,每隔固定时间都会自动触发。

  • timer 定时器是到了固定时间后会执行一次,仅执行一次

  • 如果 timer 定时器要每隔间隔的时间执行,实现 ticker 的效果,使用 func (t *Timer) Reset(d Duration) bool


一个示例:


package main


import (


“fmt”


“sync”


“time”


)func main() {


var wg sync.WaitGroup timer1 := time.NewTimer(2 * time.Second)


ticker1 := time.NewTicker(2 * time.Second) wg.Add(1)


go func(t *time.Ticker) {


defer wg.Done()


for {


<-t.C


fmt.Println(“exec ticker”, time.Now().Format(“2006-01-02 15:04:05”))


}


}(ticker1) wg.Add(1)


go func(t *time.Timer) {


defer wg.Done()


for {


<-t.C


fmt.Println(“exec timer”, time.Now().Format(“2006-01-02 15:04:05”))


t.Reset(2 * time.Second)


}


}(timer1) wg.Wait()


}01


wait 包中的核心代码


核心代码


k8s.io/apimachinery/pkg/util/wait/wait.go:


func JitterUntil(f func(), period time.Duration, jitterFactor float64, sliding bool, stopCh <-chan struct{}) {


var t *time.Timer


var sawTimeout bool


for {


select {


case <-stopCh:


return


default:


} jitteredPeriod := period


if jitterFactor > 0.0 {


jitteredPeriod = Jitter(period, jitterFactor)


} if !sliding {


t = resetOrReuseTimer(t, jitteredPeriod, sawTimeout)


} func() {


defer runtime.HandleCrash()


f()


}() if sliding {


t = resetOrReuseTimer(t, jitteredPeriod, sawTimeout)


} select {


case <-stopCh:


return


case <-t.C:


sawTimeout = true


}


}


}…


func resetOrReuseTimer(t *time.Timer, d time.Duration, sawTimeout bool) *time.Timer {


if t == nil {


return time.NewTimer(d)


}


if !t.Stop() && !sawTimeout {


<-t.C


}


t.Reset(d)


return t


}几个关键点的说明:


  1. 如果 sliding 为 true,则在 f() 运行之后计算周期。如果为 false,那么 period 包含 f() 的执行时间。

  2. 在 golang 中 select 没有优先级选择,为了避免额外执行 f(),在每次循环开始后会先判断 stopCh chan。


K8s 中 wait 包其实是对 time.Timer 做了一层封装实现。


02


wait 包常用的方法


定期执行一个函数,永不停止,可以使用 Forever 方法:


func Forever(f func(), period time.Duration)


在需要的时候停止循环,那么可以使用下面的方法,增加一个用于停止的 chan 即可,方法定义如下:


func Until(f func(), period time.Duration, stopCh <-chan struct{})


上面的第三个参数 stopCh 就是用于退出无限循环的标志,停止的时候我们 close 掉这个 chan 就可以了。


有时候,我们还会需要在运行前去检查先决条件,在条件满足的时候才去运行某一任务,这时候可以使用 Poll 方法:


func Poll(interval, timeout time.Duration, condition ConditionFunc)


这个函数会以 interval 为间隔,不断去检查 condition 条件是否为真,如果为真则可以继续后续处理;如果指定了 timeout 参数,则该函数也可以只常识指定的时间。


PollUntil 方法和上面的类似,但是没有 timeout 参数,多了一个 stopCh 参数,如下所示:


PollUntil(interval time.Duration, condition ConditionFunc, stopCh <-chan struct{}) error


此外还有 PollImmediate 、 PollInfinite 和 PollImmediateInfinite 方法。


03


总结


本文主要讲了 K8s 中定时任务的实现与对应包(wait)中方法的使用。


通过阅读 K8s 的源代码,可以发现 K8s 中许多功能的实现也都是我们需要在平时工作中用的,其大部分包的性能都是经过大规模考验的,通过使用其相关的工具包不仅能学到大量的编程技巧也能避免自己造轮子。


原文:https://dwz.cn/5zxd9ZqU


2020-01-10 13:531485

评论

发布
暂无评论
发现更多内容

Java 注解与反射 基础

卢衍飞

Java

一个PMO从0-1建设的工作思路 | 对你绝对有用!

PMO实践

项目管理 PMO

链上挖矿分红智能合约DAPP系统开发部署模式定制

开发微hkkf5566

Springboot超详细入门

陈老老老板

spring-boot 11月月更

SpringBoot整合Quartz

陈老老老板

定时任务 spring-boot 11月月更

Java 反射

卢衍飞

Java

极客时间运维进阶训练营第五周作业

9527

JavaScript 基础

卢衍飞

JavaScript 学习 技术交流 基础

从源码角度看React-Hydrate原理

flyzz177

React

Spring中获取bean的八种方式,你get了几种?

小小怪下士

Java spring bean

Java 线程基础

卢衍飞

Java

深度分析React源码中的合成事件

goClient1992

React

经营型项目经理是不是伪需求?

PMO实践

项目管理 敏捷 PMO 项目经理

ISV 的亚马逊云科技 marketplace ( 中国区) 之旅

亚马逊云科技 (Amazon Web Services)

亚马逊云科技 Tech 专栏 Marketplace

从 Uber 数据泄露事件我们可以学到什么?

SEAL安全

数据安全 企业安全 PAM

BSN开放联盟链“武汉链”新版浏览器wuscan.io正式上线发布

BSN研习社

BSN 武汉链

HDC2022的无障碍参会体验,手语服务是如何做到的?

HarmonyOS SDK

HMS Core

Timers和进程在Client里的性能表现实战心得【Node.js】

恒山其若陋兮

前端 11月月更

聊一聊装饰者模式

Java 设计模式

横向对比主流BI软件优势,企业要按需选择

巷子

好好的系统,为什么要分库分表?

程序员小富

Java 数据库 面试 分库分表

SpringBoot整合EasyExcel超详细教学

陈老老老板

spring-boot 11月月更

C++中的代码重用

Maybe_fl

转化10亿GMV:螺丝钉也能变小马达

博文视点Broadview

React-Hooks源码深度解读

goClient1992

React

看透react源码之感受react的进化

goClient1992

React

只需5步注册成为亚马逊云科技 Marketplace (海外区)专家

亚马逊云科技 (Amazon Web Services)

亚马逊云科技 Tech 专栏 Marketplace

Web3领域首个三消小游戏Matching Game,近30日交易量破800万U

股市老人

MongoDB源码学习:Command的执行与注册

云里有只猫

mongodb 源码学习

瓴羊Quick BI,强劲数据引擎助力企业数据分析

夏日星河

Kubernetes 中定时任务的实现_语言 & 开发_华为云原生团队_InfoQ精选文章