結合簡單的控制檯程序和K8S的cronjob完成定時任務

前言

老黃前段時間遇到了一個數據清洗的需求,其實就是每天凌晨把昨天的數據清洗一遍,歸歸類。

這是一個比較典型的定時任務的處理場景。

定時任務可以說就一把利器,幾乎每個公司都離不開,它的應用場景也不在少數,比如:

  1. 生成前一天的統計數據
  2. 每隔幾天清理一次日誌
  3. 定期處理失效的單據
  4. ...

對於定時任務,常見的解決方案有下面幾種

  1. quartz.net
  2. hangfire
  3. xxl-job
  4. saturn
  5. ...

對於1和2,無疑是要投入學習成本的,要習慣它們的用法,不好的地方就是不能讓開發人員集中精力去處理業務上面的內容。

對於3和4,這兩個算是分佈式任務調度的平臺,很好的與業務解耦了,可以通過HTTP的接口來觸發任務的執行。

3和4想在生產環境高可用,離不開集羣部署,在資源緊張的時候其實想部署這麼一套東西其實還是挺不容易的。

對於上面的幾種方案,老黃都沒有采用,卻而代之的是k8s的cronjob。

爲什麼選擇cronjob

上面提到的幾種方案,也已經表達了不選用的原因了,無非就是成本和複雜度,下面來講講選擇k8s的cronjob的原因吧。

首先k8s的cronjob本身就可以當作是一個任務調度的平臺了,調度的時候會創建一個POD來執行我們的任務。

其次的話,沒有複雜的依賴關係,只要編寫一個簡單的控制檯程序就好了。

還有一個是成本問題,老黃公司用的k8s是serverless的,沒有實實在在的服務器資源,交付的只是鏡像,執行這些定時任務,都是按時間計費的。

1C2G的配置只要0.00006126塊錢一秒,假設你的任務執行要3分鐘,那這一次任務只要1毛錢就可以了。

選擇什麼配置,最後要看的還是你業務的需要。

說了這麼多,來個僞例子吧。

簡單例子

要先準備一下我們的任務內容,其實就是寫個簡單的控制檯程序。

using System;

internal class Program
{
    private static void Main(string[] args)
    {
        // 寫這個定時任務要處理的內容
        
        Console.WriteLine($"Hello World!  {a}");
    }
}

這裏有一個要注意的是,不要出現 Console.ReadLine, Console.ReadKey之類的東西,不然是run不起來的。

Dockerfile就不寫了,只要能把這個控制檯程序打包成一個鏡像,可以run起來就可以了。

後面就是寫cronjob的配置了。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  labels:
    etl: diagnosis
  name: xyzxyz
  namespace: prod
spec:
  # 禁止併發運行
  concurrencyPolicy: Forbid
  failedJobsHistoryLimit: 1
  jobTemplate:
    metadata: {}
    spec:
      # 指定存活時長
      activeDeadlineSeconds: 1200
      # 指定失敗時可以重試2次
      backoffLimit: 2
      completions: 1
      parallelism: 1
      template:
        spec:
          containers:
            - env:
                - name: DOTNET_RUNNING_IN_CONTAINER
                  value: 'true'
                - name: TZ
                  value: Asia/Shanghai
              image: >-
                xxxxx:5000/xxxxx:version
              imagePullPolicy: IfNotPresent
              name: xyzxyz
              ports:
                - containerPort: 80
                  protocol: TCP
              resources:
                # 這裏只用了0.25C 0.5G
                requests:
                  cpu: 250m
                  memory: 512Mi
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          restartPolicy: Never
          schedulerName: default-scheduler
  # cron表達式,
  schedule: 22 4 1/1 * ?
  # 成功job歷史顯示個數
  successfulJobsHistoryLimit: 1

裏面的配置其實還是挺多的,對老黃的場景來說,上面的配置足夠了,對更多的配置,可以參考k8s的官網。

執行kubectl apply -f xxx.yml 就可以創建定時任務了,後面就會自動調度執行對應的任務了。

這裏就不執行了,直接拿線上正在跑的三個定時任務給大家參考一下。

點詳情可以看到具體的執行情況。

寫在最後

定時任務這個問題的答案有很多種解法,可以選擇適合公司的最優解。

因爲每種解法都有它好或者不好的地方,k8s的cronjob也是有它不足的地方的,最爲明顯的就是cron表達式第1位是分鐘而不是秒,也就是說最小粒度只到分鐘,如果你的應用需要到秒的,可能就沒辦法支持到了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章