首頁 > 軟體

Linux 定時任務 crontab 和 Systemd Timer 詳解

2020-06-16 16:36:11

一、說說八卦

?說到定時任務,我們常用的就是 crond 服務,但是我們不知道還有另外一種定時方式,那就是 systemd,我們常用 systemd 來管理我們的服務,但是我們卻不知道,我們還可以通過 systemd 來設定定時任務。本文將記錄下 crond 服務和 systemd服務來設定定時任務。 (at 命令使用較少,在此未記錄)

二 、crond服務

我們常用的定時任務就是 crond 服務,crontabcrond 服務的常用命令,我們經常通過該服務來定時或者周期性幫我們執行一些任務。

crond 服務的一些基本概念

crond 讀取組態檔會從以下幾個路徑讀取:

  • /var/spool/cron/ , 由crontab -e 進行寫入,組態檔無需指定使用者
  • /etc/crontab ,只能root 進行編輯,組態檔需指定使用者
  • /etc/cron.d/ ,在此資料夾下建立定時任務檔案,組態檔需指定使用者

crond 服務的常用檔案:

  • /var/spool/cron/

  • /etc/crontab

  • /etc/cron.d/

  • /var/log/cron # crond 服務紀錄檔位置

  • /etc/cron.deny # 禁止使用 crond 服務的賬號,預設建立的使用者是允許使用 crond 服務的。

    要禁止某個使用者,就直接將該使用者名稱寫入該檔案

crontab 常用命令

# 檢視當前的 crontab 任務
crontab -l
# 編輯 crontab 任務,不符合規則的任務會報錯。
crontab -e
# 幫助其他使用者檢視/編輯 crontab 任務,只有 root 使用者才可以使用。
crontab -u username -l # 檢視
crontab -u username -e # 編輯
# 刪除所有的 crontab 任務
crontab  -r
# crond 服務狀態
systemctl status  crond
# crond 服務啟動/暫停/重新啟動
systemctl start/stop/reload  crond

crontab 定時任務基本語法

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  *   command to be executed
字元含義
* 任何時刻,放在分鐘位置上就表示每分鐘。放在小時位置就表示每小時。
, 分割時段,比如要在3點和6點都執行,就可以寫 3,6
- 表示一個區間,比如要1點到5點的20分都執行任務,20 1-5 * * * command
/n n代表的是數位,表示每隔 n 個時間執行一次。 比如要每2分鐘執行任務,*/2 * * * * command

crontab -e (/var/spool/cron) 設定

crontab -e 命令是會檢查語法的,語法錯誤的話,是會不通過的,crontab -e 儲存在 /var/spool/cron 資料夾下,並且是以建立使用者命名的,比如我們root 使用者建立的定時任務就是儲存在 `/var/spool/cron/root

crontab 使用範例:

以下命令都是通過crontab -e 進行編輯的

  1. 要在每天23點10分和1點10分對資料庫進行備份,資料庫備份指令碼為 /opt/scripts/back.sh

    10 23,1 * * * /opt/scripts/back.sh
  2. 要在 0點到6點 每隔2小時 對資料庫進行備份,資料庫備份指令碼為 /opt/scripts/back.sh

    0 0-6/2 * * * /opt/scripts/back.sh

/etc/crontab 設定

/etc/crontab 的語法格式和 crontab -e 大致相同,前者需要指定使用者,後者不需要。

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root # 指的就是當有 stdout 和 stderr 時,傳送mail 給誰,預設是root,我們可以指定我們的e-mail賬號,但是前提要在本地設定好郵件傳送賬號
*  *  *  *  * user-name  command to be executed
#範例:25-32/2 * * * * root  /opt/test.sh

/etc/cron.d/ 設定

/etc/cron.d/下建立一個檔案,檔案設定和/etc/crontab 是一樣的,需要指定使用者。

注意點:

在 Linux 底下的 crontab 會自動的幫我們每分鐘重新讀取一次 /etc/crontab 的例行工作事項,但是某些原因或者是其他的 Unix 系統中,由於 crontab 是讀到記憶體當中的,所以在你修改完 /etc/crontab 之後,可能並不會馬上執行, 這個時候請重新啟動 crond 這個服務吧!『systemctl restart crond』

我們在設定計劃任務時需要注意一個問題,就是 如果我們設定了月日,就不要設定星期,這兩者是衝突的,只能同時存在一個。

* 15 * * 1-5 /usr/local/bin/tea_time.sh

該指令碼表示,每週一到週五下午3點,3點的每分鐘執行一次指令碼 /usr/local/bin/tea_time.sh

三 、systemd 服務

之前對於systemd 具有定時任務的功能還是只有耳聞,並沒有實際操作過,今天進行實際操作了下,發現也不錯的。

systemd 實際是通過定義一個timer單元來建立一個定時任務。它包含了兩大內容,首先定義一個service單元,這個service單元定義了我們想定時執行的任務。然後再定義一個timer單元,通過timer單元定義定時規則去執行之前的service單元。

1. 建立定時指令碼

首先我們建立一個指令碼叫做 now_time.sh,指令碼內容就是輸出當時的時間:

cat <<EOF >/opt/now_time.sh
#!/bin/bash
echo "$(date)" >>/tmp/time_record.log
EOF
chmod 755 /opt/now_time.sh  # 注意一定要更改許可權,否則後面會由於沒有執行許可權而報錯

2. 建立 Service 單元

然後需要建立一個 Service單元 timerecord

cat <<EOF >/usr/lib/systemd/system/timerecord.service 
[Unit]
Description=now time service

[Service]
ExecStart=/opt/now_time.sh

[Install]
WantedBy=multi-user.target
EOF

然後把 timerecord 作為系統服務。

systemctl start timerecord

3. 建立 Timer 單元

在建立 Timer單元前,我們需要先了解下如何設定 Timer,

[Unit] # 定義後設資料
[Timer] #定義定時器
OnActiveSec:定時器生效後,多少時間開始執行任務
OnBootSec:系統啟動後,多少時間開始執行任務
OnStartupSec:Systemd 進程啟動後,多少時間開始執行任務
OnUnitActiveSec:該單元上次執行後,等多少時間再次執行
OnUnitInactiveSec: 定時器上次關閉後多少時間,再次執行
OnCalendar:基於絕對時間,而不是相對時間執行,用於和 crond 類似的定時任務 ,以實際時間執行。
AccuracySec:如果因為各種原因,任務必須推遲執行,推遲的最大秒數,預設是60秒
Unit:真正要執行的任務,預設是同名的帶有.service字尾的單元
Persistent:如果設定了該欄位,即使定時器到時沒有啟動,也會自動執行相應的單元
WakeSystem:如果系統休眠,是否自動喚醒系統

範例:

  1. 在系統啟動15分鐘後啟動,並在系統執行時,每週啟動一次。

    [Unit]
    Description=Run foo weekly and on boot
    
    [Timer]
    OnBootSec=15min
    OnUnitActiveSec=1w 
    
    [Install]
    WantedBy=timers.target
  2. 每週執行一次(周一凌晨0點)。啟用後,如果錯過了上次啟動時間,,它會立即觸發服務,例如由於系統斷電:

    [Unit]
    Description=Run foo weekly
    
    [Timer]
    OnCalendar=weekly
    Persistent=true
    
    [Install]
    WantedBy=timers.target
  3. 每天周一下午3點10分執行

    如果需要具體的時間,我們可以給OnCalendar 設定具體時間值,形如 Year-Month-Day Hour:Minute:Second

    [Unit]
    Description=Run timerecord on Monday 3:10
    
    [Timer]
    OnCalendar=Mon *-*-* 15:10:00
    Unit=timerecord
    
    [Install]
    WantedBy=timers.target
  4. 每隔5秒執行一次

    [Unit]
    Description=Run timerecord  every 5s
    
    [Timer]
    OnUnitActiveSec=5s # 可以設定為 5m,1h
    Unit=timerecord
    
    [Install]
    WantedBy=timers.target
    
  5. 每個小時的每隔10分鐘 進行備份服務

    [Unit]
    Description=backup
    
    [Timer]
    OnCalendar=*-*-* 0/1:0/10:00
    Unit=backup
    
    [Install]
    WantedBy=multi-user.target
    

建立 Timer 單元 record:每隔1分鐘執行一次

cat <<EOF > /usr/lib/systemd/system/timerecord.timer
[Unit]
Description=Run timerecord  every 5s

[Timer]
OnUnitActiveSec=1m # 可以設定為 5m,1h
Unit=timerecord #指定 Service 服務名

[Install]
WantedBy=timers.target
EOF

啟用定時任務

systemctl  daemon-reload  #重新載入設定
systemctl  start  timerecord.timer # 啟動定時任務

常用命令:

systemctl  start  timerecord.timer# 啟動定時任務
systemctl  stop  timerecord.timer# 暫停定時任務
systemctl  status  timerecord.timer# 檢視定時任務服務狀態
systemctl  restart  timerecord.timer# 重新啟動定時任務狀態
systemctl list-timers --all # 檢視定時任務列表
systemctl  daemon-reload  # 更改了組態檔後,需要重新載入
journalctl -u mytimer.timer # 檢視 mytimer.timer 的紀錄檔
journalctl -u mytimer # 檢視 mytimer.timer 和 mytimer.service 的紀錄檔
journalctl -f # 從結尾開始檢視最新紀錄檔
journalctl -f -u timer.timer #  從結尾開始檢視 mytimer.timer 的紀錄檔

IT145.com E-mail:sddin#qq.com