写点什么

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:531641

评论

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

时序数据库DolphinDB与Druid的对比测试

DolphinDB

数据分析 时序数据库 Druid 数据库选择 DolphinDB

甲方日常 65

句子

工作 随笔杂谈 日常

话题讨论 | 选择做一个程序员,你后悔过吗?

xcbeyond

话题讨论

Mybatis 中xml和注解映射,这次终于搞明白了

田维常

mybatis

话题讨论 | 30 张图解高并发服务模型你必须这些

程序员柠檬

话题讨论

情报合成研判系统开发,智慧警务解决方案

t13823115967

智慧公安

业务中台建设-数据

孝鹏

架构 中台 数据 赋能

一文教你看懂缓存穿透、击穿、雪崩、降级等异常

鄙人薛某

Java 缓存 后端 缓存击穿 缓存雪崩

网咯请求中的 connectTimeout 和 soTimeout

不在调上

P8架构挑战:七大专题1425页考点,你能成功吗?

小Q

Java 学习 程序员 架构 面试

operator-sdk & kubebuilder

QiLab

k8s operator-sdk kubebuilder crd

开发实践丨用小熊派STM32开发板模拟自动售货机

华为云开发者联盟

物联网 小熊派 开发板

英特尔携手德晟达、游密,发布云会议终端解决方案,打造视听新体验

E科讯

原创 | 使用JPA实现DDD持久化-领域模型:对象的世界

编程道与术

Java hibernate 编程 mybatis jpa

区块链司法存证应用落地应用解决方案

t13823115967

区块链落地开发

话题讨论 | 立一个近期的flag,你会想到什么?

xcbeyond

话题讨论

原创 | 使用JPA实现DDD持久化-O/R映射元数据:映射注解分组

编程道与术

Java hibernate 编程 mybatis jpa

全球熵ETV系统APP软件开发

系统开发

可见性是什么?(通俗易懂)

叫练

volatile JMM 多线程 synchronized

北京奥森小景

小马哥

摄影 美景 奥森 28天写作

安装MySQL后,需要调整的10个性能配置项

Simon

MySQL percona server

关于Kubernetes和Docker关系的八个问题

杨明越

如何预防勒索攻击事件?这份安全自查指南请查收

京东科技开发者

数据安全 数据加密 系统安全

人脸识别是如何实现的

anyRTC开发者

ios 音视频 WebRTC 人脸识别 安卓

《算法导论》.pdf

田维常

原创 | 使用JPA实现DDD持久化-O/R映射元数据:类级映射-实体和值对象

编程道与术

Java hibernate 编程 mybatis jpa

不满意社区的轮子,我们自创了一套 React Hooks 风格的数据加载方案

LeanCloud

API React Hooks

没有它你的DevOps是玩不转的,你信不?

华为云开发者联盟

容器 DevOps 微服务

《css大法》之使用伪元素实现超实用的图标库(附源码)

徐小夕

CSS css3 大前端 CSS小技巧

使用JPA实现DDD持久化-O/R映射元数据-特殊属性映射:ID、Version和Transient

编程道与术

Java hibernate 编程 mybatis jpa

Java架构速成笔记:七大专题,1425页考点,挑战P8岗

Java架构追梦

Java 学习 面试 java架构

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