0、基本概念 & 實現原理
定時任務基本概念:
- 調度器:負責管理Quartz應用運行時環境,用於調度定時任務。
- 定時任務:按照某種時間規則,被調度的任務。
a、從有無狀態來說,有以下兩種:
有狀態任務:每次執行的任務是同一個實例,不能被並行執行;如果該任務的執行時間超過下次觸發的時刻,那么下次的觸發將不會有作用。比如,一個有狀態任務執行時間是5分鍾,它的間隔時間是3分鍾;如果正在執行的時候,下次觸發時刻到達,則不會被執行。
無狀態任務:每次執行任務都是一個新的實例,可以並行執行。
b、從執行的任務類型來說,有以下三種:
SCA服務任務:任務是一個SCA服務。
邏輯流任務:任務是一個邏輯流。
任意方法任務:任務是一個方法。
c、觸發模式(觸發器):用於定義任務調度的時間規則,主要有下面兩種:
固定時刻觸發(簡單觸發器):一般用於實現間隔固定的時間執行任務,以及重復多少次,如每 2 小時執行一次,重復執行 5 次。
日歷周期觸發(復雜觸發器):使用Unix 'cron-like'表達式來定義時間規則,即利用一個包含 7 個字段的表達式來表示時間調度方式。例如,"0 15 10 * * ? *" 表示每天的 10:15AM 執行任務。對於涉及到星期和月份的調度比較合適。
d、錯失觸發:定時任務如果錯過觸發而沒有執行,比如系統停止;系統重啟后,就會針對錯失觸發的定時任務進行處理,一般有兩種錯失觸發策略(EOS_QRTZ_TRIGGERS表的MISFIRE_INSTR字段):
立即重新觸發:默認策略,立即執行一次定時任務,而不管錯過幾次。MISFIRE_INSTR字段值為1。
錯過觸發:下次觸發時間到來,再觸發執行定時任務。MISFIRE_INSTR字段值為2。
定時任務配置界面如下:
定時任務的實現:
- 單機模式:調度器啟動一個調度線程,根據觸發器進行輪詢,如果觸發時刻到達,分配一個執行線程,執行定時任務。其中調度器及其狀態、觸發器及其狀態、定時任務及其狀態信息都會持久化到數據庫中,所以系統停止,不會丟失定時任務;系統重新啟動,會重新定時觸發。
- 集群模式:定時任務的集群,有負載均衡和故障切換的能力,可以給調度器帶來高可用性和伸縮性。集群管理的實現是,集群上的每一個節點通過共享同一個數據庫來工作的(Quartz通過啟動兩個維護線程來維護數據庫狀態實現集群管理,一個是檢測節點狀態線程,一個是恢復任務線程),通過數據庫鎖來實現並發控制(如果不是集群,使用內存鎖進行並發控制)。負載均衡是自動完成的,集群的每個節點會盡快觸發任務。當一個觸發器的觸發時間到達時,第一個節點將會獲得任務,並改變任務狀態,成為執行任務的節點。故障切換的發生是在當一個節點正在執行一個或者多個任務失敗的時候。當一個節點失敗了,其他的節點會檢測到並且標識在失敗節點上正在進行的數據庫中的任務。任何被標記為可恢復的任務都會被其他的節點重新執行。沒有標記可恢復的任務只會被釋放出來,將會在下次相關觸發器觸發時執行。
注: 如果是集群模式,則要求每個節點的時鍾一定要一致,否則將發生無法預料的問題。建議簡單觸發器的間隔時間不要小於20秒。
Cron 是一個linux下的定時執行工具,也是Linux的內置服務,可以在不用人工干預的情況下運行作業。
/sbin/service crond start # 啟動服務
/sbin/service crond stop # 關閉服務
/sbin/service crond restart # 重啟服務
/sbin/service crond reload # 重新載入配置
在 /etc/rc.d/rc.local 這個腳本的末尾加上: /sbin/service crond start 那么Cron這個服務就已經在進程里面了,我們就可以用這個服務了。
Cron提供的接口:
使用crontab命令編輯, cron服務提供crontab命令來設定cron服務的,參數說明:
crontab -u # 設定某個用戶的cron服務,一般root用戶在執行這個命令的時候需要此參數
crontab -l # 列出某個用戶cron服務的詳細內容
crontab -r # 刪除每個用戶的cron服務
crontab -e # 編輯某個用戶的cron服務
root查看自己的cron設置: crontab -u root -l
root刪除fred的cron設置: crontab -u fred -r
編輯cron服務的格式和約定: crontab -u root -e
進入vi編輯模式: */1 * * * * ls >> /tmp/ls.txt
crontab命令選項:
-u 指定一個用戶,
-l 列出某個用戶的任務計划,
-r 刪除某個用戶的任務,
-e 編輯某個用戶的任務
任務調度的crond常駐命令:crond 是linux用來定期執行程序的命令。操作系統安裝完成之后,默認會啟動此任務的調度命令。crond命令每分鍾會定期檢查是否有要執行的工作,如果有要執行的工作便會自動執行該工作。
Linux任務調度的工作主要分為以下兩類:
- 系統執行的工作:系統周期性所要執行的工作,如備份系統數據、清理緩存
- 個人執行的工作:某個用戶定期要做的工作,例如每隔10分鍾檢查郵件服務器是否有新信,這些工作可由每個用戶自行設置。
cron服務每分鍾不僅要讀一次 /var/spool/cron 內的所有文件,還需要讀一次 /etc/crontab ,因此我們配置這個文件也能運用cron服務做一些事情。用crontab配置是針對某個用戶的,而編輯 /etc/crontab 是針對系統的任務。
原理解析
Cron服務是由 守護進程crond和一組crontab文件 組成。crond守護進程是在系統啟動時由init進程啟動的,受init進程的監視,如果它不存在了,會被init進程重新啟動。這個守護進程每分鍾喚醒一次,並通過檢查crontab文件(任務表)判斷需要執行什么任務。每個用戶有一個以用戶名命名的crontab文件,存放在 /var/spool/cron/crontabs 目錄里。若管理員允許或者禁止其他用戶擁有crontab文件,則應編輯 /etc/cron.deny 和 etc/cron.allow 這兩個文件來禁止或允許用戶擁有自己的 crontab文件。(每一個用戶都可以有自己的crontab文件,但在一個較大的系統中,系統管理員一般會禁止這些文件,而只在整個系統保留一個這樣的文件)
crontab實際上是啟動服務后讀取所有配置文件,然后睡眠一分鍾之后運行下一個任務,crontab服務啟動后,會檢查 /var/spool/cron/tabs 下所有用戶的定時任務,然后加載到內存的隊列中,然后每分鍾檢查一下 crontab文件是否有改動。可以理解為cron服務有2個線程,一個是調度處理定時任務,一個后台線程,后台線程檢查配置文件是否有變動,如果有變動,則發送信號到調度進程,調度進程再重新讀取配置文件更新內存中的任務隊列,同理,service cron stop 也是發信號到cron服務(本次確認cron服務半僵死就是因為無法響應了)導致調度線程不知道變動,沒有更新內存中的隊列。從 /var/log/messages 觀察,依然是修改或刪除之前的定時任務在運行。 因此,為了保險,在用戶里 crontab -r 刪除用戶的定時任務后,建議重啟一下crontab服務(service cron stop后記得service cron status 查看一下是否停止成功,如果沒有 kill -9 再 service cron start),也就是清空一下當前定時任務的內存隊列,讓cron服務重新加載,更重要的是防止cron服務掛住沒重新加載定時任務隊列。
3.cron文件語法:
分 小時 日 月 星期 命令
0-59 0-23 1-31 1-12 0-6 command (取值范圍,0表示周日一般一行對應一個任務)
4.記住幾個特殊符號的含義:
"*" 代表取值范圍內的數字,
"/" 代表"每",
"-" 代表從某個數字到某個數字,
"," 分開幾個離散的數字 一、任務調度設置文件的寫法 可用crontab -e命令來編輯,編輯的是/var/spool/cron下對應用戶的cron文件,也可以直接修改/etc/crontab文件 具體格式如下:
Minute Hour Day Month Dayofweek command
分鍾 小時 天 月 天每星期 命令 每個字段代表的含義如下:
Minute 每個小時的第幾分鍾執行該任務
Hour 每天的第幾個小時執行該任務
Day 每月的第幾天執行該任務
Month 每年的第幾個月執行該任務
DayOfWeek 每周的第幾天執行該任務
Command 指定要執行的程序 在這些字段里,除了“Command”是每次都必須指定的字段以外,其它字段皆為可選字段,可視需要決定。對於不指定的字段,要用“*”來填補其位置。 舉例如下:
5 * * * * ls 指定每小時的第5分鍾執行一次ls命令
30 5 * * * ls 指定每天的 5:30 執行ls命令
30 7 8 * * ls 指定每月8號的7:30分執行ls命令
30 5 8 6 * ls 指定每年的6月8日5:30執行ls命令
30 6 * * 0 ls 指定每星期日的6:30執行ls命令[注:0表示星期天,1表示星期1,以此類推,也可以用英文來表示,sun表示星期天,mon表示星期一等。]
30 3 10,20 * * ls 每月10號及20號的3:30執行ls命令[注:“,”用來連接多個不連續的時段]
25 8-11 * * * ls 每天8-11點的第25分鍾執行ls命令[注:“-”用來連接連續的時段]
*/15 * * * * ls 每15分鍾執行一次ls命令 [即每個小時的第0 15 30 45 60分鍾執行ls命令 ]
30 6 */10 * * ls 每個月中,每隔10天6:30執行一次ls命令[即每月的1、11、21、31日是的6:30執行一次ls命令。 ]
每天7:50以root 身份執行/etc/cron.daily目錄中的所有可執行文件
50 7 * * * root run-parts /etc/cron.daily [ 注:run-parts參數表示,執行后面目錄中的所有可執行文件。 ]
二、新增調度任務 新增調度任務可用兩種方法:
1、在命令行輸入: crontab -e 然后添加相應的任務,wq存盤退出。
2、直接編輯/etc/crontab 文件,即vi /etc/crontab,添加相應的任務。 三、查看調度任務
crontab -l //列出當前的所有調度任務
crontab -l -u jp //列出用戶jp的所有調度任務 四、刪除任務調度工作
crontab -r //刪除所有任務調度工作 五、任務調度執行結果的轉向 例1:每天5:30執行ls命令,並把結果輸出到/jp/test文件中
30 5 * * * ls >/jp/test 2>&1
注:2>&1 表示執行結果及錯誤信息。 編輯/etc/crontab 文件配置cron
系統任務格式:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root //如果出現錯誤,或者有數據輸出,數據作為郵件發給這個帳號 HOME=/ //使用者運行的路徑,這里是根目錄
# run-parts
01 * * * * root run-parts /etc/cron.hourly
//每小時執行/etc/cron.hourly內的腳本
02 4 * * * root run-parts /etc/cron.daily
//每天執行/etc/cron.daily內的腳本
22 4 * * 0 root run-parts /etc/cron.weekly
//每星期執行/etc/cron.weekly內的腳本
42 4 1 * * root run-parts /etc/cron.monthly
//每月去執行/etc/cron.monthly內的腳本
大家注意"run-parts"這個參數了,如果去掉這個參數的話,后面就可以寫要運行的某個腳本名,而不是文件夾名了
例如:
1、在命令行輸入: crontab -e 然后添加相應的任務,wq存盤退出。
2、直接編輯/etc/crontab 文件,即vi /etc/crontab,添加相應的任務
11 2 21 10 * rm -rf /mnt/fb
一、相關配置
- /var/spool/cron/ 用於存放每個用戶包括root的crontab任務,每個任務以創建者的名字命名
- /etc/crontab 此文件負責調度各種管理和維護任務。
- /etc/cron.d/ 用於存放任何要執行的crontab文件或腳本。
- /etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly 用於存放腳本,可讓它每小時/天/星期、月執行一次。
二、常用命令:
crontab [-u username] // 省略用戶表表示操作當前用戶的crontab -e (編輯工作表) -l (列出工作表里的命令) -r (刪除工作)
crontab -e 進入當前用戶的工作表編輯,crontab的命令構成為‘時間+動作’,其時間有分、時、日、月、周五種,操作符有:
- * 取值范圍內的所有數字
- / 每過多少個數字
- - 從X到Z
- ,散列數字
三、crontab時間說明
# .---------------- 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 # | | | | | # | | | | | # * * * * * command to be executed minute:代表一小時內的第幾分,范圍 0-59。 hour:代表一天中的第幾小時,范圍 0-23。 mday:代表一個月中的第幾天,范圍 1-31。 month:代表一年中第幾個月,范圍 1-12。 wday:代表星期幾,范圍 0-7 (0及7都是星期天)。 who:要使用什么身份執行該指令,當您使用 crontab -e 時,不必加此字段。 command:所要執行的指令。
四、crontab服務狀態
sudo service crond start # 啟動服務 sudo service crond stop # 關閉服務 sudo service crond restart # 重啟服務 sudo service crond reload # 重新載入配置 sudo service crond status # 查看服務狀態
五、crontab命令
crontab $filepath # 重新指定crontab定時任務列表文件 crontab -l # 查看crontab定時任務 crontab -e # 編輯定時任務【刪除-添加-修改】 # 添加定時任務 Step-One : 編輯任務腳本【分目錄存放】【ex: backup.sh】 Step-Two : 編輯定時文件【命名規則:backup.cron】 Step-Three : crontab命令添加到系統crontab backup.cron Step-Four : 查看crontab列表 crontab -l
六、實例
# 實例1:每1分鍾執行一次myCommand * * * * * myCommand # 實例2:每小時的第3和第15分鍾執行 3,15 * * * * myCommand # 實例3:在上午8點到11點的第3和第15分鍾執行 3,15 8-11 * * * myCommand # 實例4:每隔兩天的上午8點到11點的第3和第15分鍾執行 3,15 8-11 */2 * * myCommand # 實例5:每周一上午8點到11點的第3和第15分鍾執行 3,15 8-11 * * 1 myCommand # 實例6:每晚的21:30重啟smb 30 21 * * * /etc/init.d/smb restart # 實例7:每月1、10、22日的4 : 45重啟smb 45 4 1,10,22 * * /etc/init.d/smb restart # 實例8:每周六、周日的1 : 10重啟smb 10 1 * * 6,0 /etc/init.d/smb restart # 實例9:每天18 : 00至23 : 00之間每隔30分鍾重啟smb 0,30 18-23 * * * /etc/init.d/smb restart # 實例10:每星期六的晚上11 : 00 pm重啟smb 0 23 * * 6 /etc/init.d/smb restart # 實例11:每一小時重啟smb * */1 * * * /etc/init.d/smb restart # 實例12:晚上11點到早上7點之間,每隔一小時重啟smb * 23-7/1 * * * /etc/init.d/smb restart # 每天早上6點 0 6 * * * echo "Good morning." >> /tmp/test.txt //注意單純echo,從屏幕上看不到任何輸出,因為cron把任何輸出都email到root的信箱了。 # 每兩個小時 0 */2 * * * echo "Have a break now." >> /tmp/test.txt # 晚上11點到早上8點之間每兩個小時和早上八點 0 23-7/2,8 * * * echo "Have a good dream" >> /tmp/test.txt # 每個月的4號和每個禮拜的禮拜一到禮拜三的早上11點 0 11 4 * 1-3 command line # 1月1日早上4點 0 4 1 1 * command line SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root //如果出現錯誤,或者有數據輸出,數據作為郵件發給這個帳號 HOME=/ # 每小時(第一分鍾)執行/etc/cron.hourly內的腳本 01 * * * * root run-parts /etc/cron.hourly # 每天(凌晨4:02)執行/etc/cron.daily內的腳本 02 4 * * * root run-parts /etc/cron.daily # 每星期(周日凌晨4:22)執行/etc/cron.weekly內的腳本 22 4 * * 0 root run-parts /etc/cron.weekly # 每月(1號凌晨4:42)去執行/etc/cron.monthly內的腳本 42 4 1 * * root run-parts /etc/cron.monthly # 注意: "run-parts"這個參數了,如果去掉這個參數的話,后面就可以寫要運行的某個腳本名,而不是文件夾名。 # 每天的下午4點、5點、6點的5 min、15 min、25 min、35 min、45 min、55 min時執行命令。 5,15,25,35,45,55 16,17,18 * * * command # 每周一,三,五的下午3:00系統進入維護狀態,重新啟動系統。 00 15 * *1,3,5 shutdown -r +5 # 每小時的10分,40分執行用戶目錄下的innd/bbslin這個指令: 10,40 * * * * innd/bbslink # 每小時的1分執行用戶目錄下的bin/account這個指令: 1 * * * * bin/account # 每天早晨三點二十分執行用戶目錄下如下所示的兩個指令(每個指令以;分隔): 203 * * * (/bin/rm -f expire.ls logins.bad;bin/expire$#@62;expire.1st)
七、Django中的定時任務
# 添加定時任務到系統中 python manage.py crontab add # 顯示已經激活的定時任務 python manage.py crontab show # 移除定時任務 python manage.py crontab remove