• 有什么比较好的方法解决k8s 更新deploy导致计划任务丢失的问题?
  • 发布于 2个月前
  • 118 热度
    8 评论
比如一个 pod 中有一个 30 分钟后开始执行的任务,这个时候更新 deploy ,这个任务就没了.
比较简单粗暴的做法:
1. 让 pod 等 30 分钟再关闭,但是如果 30 分钟内又有 deploy 更新,会有问题
2. 把这个延时任务放到第三方组件里持久化,后面再取出来执行
但是感觉都不太优雅,有没有什么方法,不需要第三方组件,能用 k8s 本身的机制,或者在服务内部解决这个问题?
用户评论
  • Vinda
  • 你看下 pod 的 lifecycle 啊,pod 退出的时候会给你的程序发个信号,你收到信号的时候把任务取出来塞回队列里,新的 pod 再去队列拿回来就行了吧。
  • 2024/5/9 17:10:00 [ 0 ] [ 0 ] 回复
  • 耀国
  • 任务如果能做成可以断点续跑的,pod 随时干掉也没问题。如果不能做成断点续跑的,就设置一个 30 分钟的 gracefully exit 时间,rollout 的时候印象中应该会等 pod 自己退出的。但这个方案应该会一个特殊场景会有问题,某次 rollout 的时候 pod 还没 ready ,就开始执行任务了,然后紧接着又 rollout 了一个,这个时候我印象不会等 gracefully exit 直接会干掉 pod 。
  • 2024/5/9 17:01:00 [ 0 ] [ 0 ] 回复
  • 荒岛初冬
  • 任务保持在 DB 中,存储任务状态和创建时间,然后服务内部开个线程轮询 30 分钟以前的未执行的任务,更新状态为执行中,更新成功的就本地执行,更新不成功的跳过,有可能被其他 Pod 抢到了,这块的处理是上锁最好,redis 锁或者 db 锁都行。
  • 2024/5/9 16:35:00 [ 0 ] [ 0 ] 回复
  • 烂好人i
  • 任务如果能做成可以断点续跑的,pod 随时干掉也没问题。如果不能做成断点续跑的,就设置一个 30 分钟的 gracefully exit 时间,rollout 的时候印象中应该会等 pod 自己退出的。但这个方案应该会一个特殊场景会有问题,某次 rollout 的时候 pod 还没 ready ,就开始执行任务了,然后紧接着又 rollout 了一个,这个时候我印象不会等 gracefully exit 直接会干掉 pod 。
  • 2024/5/9 16:28:00 [ 0 ] [ 0 ] 回复
  • 昨日情书
  • 业务代码角度:
    任务状态和任务信息保存在 DB 中, 修改代码逻辑,在服务里面加一些请求处理,服务增加优雅关闭处理,能够处理 sigterm 的信号。

    从 k8s 角度:
    使用自定义钩子
    Deployment 资源支持以下几种钩子:
    PostStart 钩子:在容器启动后立即执行。这通常用于执行容器启动后的初始化任务,例如等待其他服务启动、注册服务到服务发现系统等。
    PreStop 钩子:在容器关闭之前执行。这通常用于执行容器关闭前的清理任务,例如保存数据、关闭连接、发送信号给其他进程等。

    在关闭之前执行一些持久化操作,比如 可以执行一个 HTTP GET 请求 或者 exec 命令,并且它们执行是阻塞的,可以利用这个特性来做优雅停止。

    调用 HTTP GET
    spec:
    contaienrs:
    - name: my-container
    lifecycle:
    preStop:
    httpGet:
    path: "/stop"
    port: 8080
    scheme: "HTTP"
    修改 terminationGracePeriodSeconds , 将它调整到合适的值,不要过大。
    terminationGracePeriodSeconds 等于 服务优雅退出超时时间和 preStopHook 之和
  • 2024/5/9 16:20:00 [ 0 ] [ 0 ] 回复
  • 陪着我走
  • 首先,pod 最好是无状态,在 k8s 里更新、扩容、重启都方便。
    第二,没有持久化的话,本身这个程序也不可靠,总会遇到异常崩溃吧。
    单纯想更新后不丢任务,可以让程序监听到 terminal 后主动找个地方存一下,启动时再去读。
  • 2024/5/9 16:17:00 [ 0 ] [ 0 ] 回复