【Python】輕量級分散式任務排程系統-RQ
一 前言
Redis Queue 一款輕量級的P分散式非同步任務佇列,基於Redis作為broker,將任務存到redis裡面,然後在後臺執行指定的Job。就目前而言有三套成熟的工具celery,huey ,rq 。按照功能和使用複雜度來排序的話也是 celery>huey>rq. 因為rq 簡單,容易上手,所以自己做的系統也會使用RQ作為分散式任務排程系統。
二 安裝
因為RQ 依賴於Redis 故需要安裝版本>= 2.6.0.具體安裝方法請參考《Redis初探》。*nix 系統環境下安裝RQ:
無需其他配置即可以使用RQ。
三 原理
RQ 主要由三部分構成 Job ,Queues,Worker 構成。job也就是開發定義的函式用來實現具體的功能。呼叫RQ 把job 放入佇列Queues,Worker 負責從redis裡面獲取任務並執行,根據具體情況返回函式的結果。
3.1 關於job
一個任務(job)就是一個Python物件,具體表現為在一個工作(後臺)程式中非同步呼叫一個函式。任何Python函式都可以非同步呼叫,簡單的將函式與引數追加到佇列中,這叫做入隊(enqueueing)。
3.2 關於Queue
將任務加入到佇列之前需要初始化一個連線到指定Redis的Queue
queue有如下屬性:
timeout :指定任務最長執行時間,超過該值則被認為job丟失,對於備份任務 需要設定一個比較長的時間 比如24h。
result_ttl :儲存任務返回值的有效時間,超過該值則失效。
ttl :specifies the maximum queued time of the job before it'll be cancelled
depends_on :specifies another job (or job id) that must complete before this job will be queued
job_id : allows you to manually specify this job's job_id
at_front :will place the job at the front of the queue, instead of the back
kwargs and args : lets you bypass the auto-pop of these arguments, ie: specify a timeout argument for the underlying job function.
需要關注的是 depends_on ,透過該屬性可以做級聯任務A-->B ,只有當A 執行成功之後才能執行B .
透過指定佇列的名字,我們可以把任務加到一個指定的佇列中:
對於例子中的Queue("low"),具體使用的時候可以替換"low"為任意的複合業務邏輯名字,這樣就可以根據業務的需要靈活地歸類的任務了。一般會根據優先順序給佇列命名(如:high, medium, low).
如果想要給enqueue傳遞引數的情況,可以使用enqueue_call方法。在要傳遞超時引數的情況下:
3.3 關於worker
Workers將會從給定的佇列中不停的迴圈讀取任務,當所有任務都處理完畢就等待新的work到來。每一個worker在同一時間只處理一個任務。在worker中,是沒有併發的。如果你需要併發處理任務,那就需要啟動多個worker。
目前的worker實際上是fork一個子程式來執行具體的任務,也就是說rq不適合windows系統。而且RQ的work是單程式的,如果想要併發執行佇列中的任務提高執行效率需要使用threading針對每個任務進行fork執行緒。
worker的生命週期有以下幾個階段組成:
1 啟動,載入Python環境
2 註冊,worker註冊到系統上,讓系統知曉它的存在。
3 開始監聽。從給定的redis佇列中取出一個任務。如果所有的佇列都是空的且是以突發模式執行的,立即退出。否則,等待新的任務入隊。
4 分配一個子程式。分配的這個子程式在故障安全的上下文中執行實際的任務(呼叫佇列中的任務函式)
5 處理任務。處理實際的任務。
6 迴圈。重複執行步驟3。
四 如何使用
簡單的開發一個deamon 函式,用於後端非同步呼叫,注意任意函式都可以加入佇列,必須能夠在入隊的時候 被程式訪問到。
4.1 構建佇列,將任務物件新增到佇列裡面
先例項化一個Queue類q,然後透過enqueue方法釋出任務。第一個引數是執行的函式名,後面是函式執行所需的引數,可以是args也可以是kwargs,案例中是一個字串。
然後會返回一個Job類的例項,後面會具體介紹Job類的例項具體的api。
4.2啟動worker ,從日誌上可以看到執行了utils.hello('yangyi') utils.hello('youzan.com') 。當然這個只是簡單的呼叫介紹,生產環境還要寫的更加健壯,針對函式執行的結果進行相應的業務邏輯處理。
需要說明的是其實 worker的啟動順序應該在job放入佇列之前,一直監聽rq裡面是否有具體的任務,當然如果worker晚於job 加入佇列啟動,job的狀態會顯示為 queued 狀態。
4.3 檢視作業執行的情況
當任務加入佇列,queue.enqueue()方法返回一個job例項。其定義位於rq.job檔案中,可以去檢視一下它的API,主要用到的API有:
五 參考文章
[1]
[2] 翻譯 - Python RQ Job
[3] 翻譯 - Python RQ Workers
[4] 這位博主寫了很多rq相關的實踐經驗,值得參考。
Redis Queue 一款輕量級的P分散式非同步任務佇列,基於Redis作為broker,將任務存到redis裡面,然後在後臺執行指定的Job。就目前而言有三套成熟的工具celery,huey ,rq 。按照功能和使用複雜度來排序的話也是 celery>huey>rq. 因為rq 簡單,容易上手,所以自己做的系統也會使用RQ作為分散式任務排程系統。
二 安裝
因為RQ 依賴於Redis 故需要安裝版本>= 2.6.0.具體安裝方法請參考《Redis初探》。*nix 系統環境下安裝RQ:
- pip install rq
三 原理
RQ 主要由三部分構成 Job ,Queues,Worker 構成。job也就是開發定義的函式用來實現具體的功能。呼叫RQ 把job 放入佇列Queues,Worker 負責從redis裡面獲取任務並執行,根據具體情況返回函式的結果。
3.1 關於job
一個任務(job)就是一個Python物件,具體表現為在一個工作(後臺)程式中非同步呼叫一個函式。任何Python函式都可以非同步呼叫,簡單的將函式與引數追加到佇列中,這叫做入隊(enqueueing)。
3.2 關於Queue
將任務加入到佇列之前需要初始化一個連線到指定Redis的Queue
-
q=Queue(connection=redis_conn)
-
from rq_test import hello
- result = q.enqueue(hello,'yangyi')
timeout :指定任務最長執行時間,超過該值則被認為job丟失,對於備份任務 需要設定一個比較長的時間 比如24h。
result_ttl :儲存任務返回值的有效時間,超過該值則失效。
ttl :specifies the maximum queued time of the job before it'll be cancelled
depends_on :specifies another job (or job id) that must complete before this job will be queued
job_id : allows you to manually specify this job's job_id
at_front :will place the job at the front of the queue, instead of the back
kwargs and args : lets you bypass the auto-pop of these arguments, ie: specify a timeout argument for the underlying job function.
需要關注的是 depends_on ,透過該屬性可以做級聯任務A-->B ,只有當A 執行成功之後才能執行B .
透過指定佇列的名字,我們可以把任務加到一個指定的佇列中:
-
q = Queue("low", connection = redis_conn)
- q.enqueue(hello, "楊一")
如果想要給enqueue傳遞引數的情況,可以使用enqueue_call方法。在要傳遞超時引數的情況下:
-
q = Queue("low", connection = redis_conn)
- q.enqueue_call(func=hello, args= ("楊一",),timeout = 30)
Workers將會從給定的佇列中不停的迴圈讀取任務,當所有任務都處理完畢就等待新的work到來。每一個worker在同一時間只處理一個任務。在worker中,是沒有併發的。如果你需要併發處理任務,那就需要啟動多個worker。
目前的worker實際上是fork一個子程式來執行具體的任務,也就是說rq不適合windows系統。而且RQ的work是單程式的,如果想要併發執行佇列中的任務提高執行效率需要使用threading針對每個任務進行fork執行緒。
worker的生命週期有以下幾個階段組成:
1 啟動,載入Python環境
2 註冊,worker註冊到系統上,讓系統知曉它的存在。
3 開始監聽。從給定的redis佇列中取出一個任務。如果所有的佇列都是空的且是以突發模式執行的,立即退出。否則,等待新的任務入隊。
4 分配一個子程式。分配的這個子程式在故障安全的上下文中執行實際的任務(呼叫佇列中的任務函式)
5 處理任務。處理實際的任務。
6 迴圈。重複執行步驟3。
四 如何使用
簡單的開發一個deamon 函式,用於後端非同步呼叫,注意任意函式都可以加入佇列,必須能夠在入隊的時候 被程式訪問到。
-
#!/usr/bin/env python
-
#-*- coding:utf-8 -*-
-
def hello(name):
-
print "hello ,%s"%name
-
ip='192.168.0.1'
-
num=1024
-
return name,ip,num
-
def workat(name):
- print "hello %s ,you r workat youzan.com "%(name)
-
>>> from redis import Redis,ConnectionPool
-
>>> from rq import Queue
-
>>> pool = ConnectionPool(db=0, host='127.0.0.1', port=6379,
-
... password='yangyi')
-
>>> redis_conn = Redis(connection_pool=pool)
-
>>> q=Queue(connection=redis_conn)
-
>>> from rq_test import hello
-
>>>
-
>>> result = q.enqueue(hello,'yangyi')
- >>> result = q.enqueue(hello,'youzan.com')
然後會返回一個Job類的例項,後面會具體介紹Job類的例項具體的api。
4.2啟動worker ,從日誌上可以看到執行了utils.hello('yangyi') utils.hello('youzan.com') 。當然這個只是簡單的呼叫介紹,生產環境還要寫的更加健壯,針對函式執行的結果進行相應的業務邏輯處理。
-
root@rac2:~# >python woker.py
-
23:44:48 RQ worker u'rq:worker:rac2.3354' started, version 0.6.0
-
23:44:48 Cleaning registries for queue: default
-
23:44:48
-
23:44:48 *** Listening on default...
-
23:44:48 default: utils.hello('yangyi') (63879f7c-b453-4405-a262-b9a6b6568b68)
-
hello ,yangyi
-
23:44:48 default: Job OK (63879f7c-b453-4405-a262-b9a6b6568b68)
-
23:44:48 Result is kept for 500 seconds
-
23:44:48
-
23:44:48 *** Listening on default...
-
23:45:12 default: utils.hello('youzan.com') (e4e9ed62-c476-45f2-b66a-4b641979e731)
-
hello ,youzan.com
-
23:45:12 default: Job OK (e4e9ed62-c476-45f2-b66a-4b641979e731)
- 23:45:12 Result is kept for 500 seconds
4.3 檢視作業執行的情況
當任務加入佇列,queue.enqueue()方法返回一個job例項。其定義位於rq.job檔案中,可以去檢視一下它的API,主要用到的API有:
-
>>> from rq import job
-
>>> job = q.enqueue(hello,'youzan.com')
-
>>> job.get_id() ##獲取任務的id ,如果沒有指定 ,系統會自動分配一個隨機的字串。
-
u'17ad0b3a-195e-49d5-8d31-02837ccf5fa6'
-
>>> job = q.enqueue(hello,'youzan.com')
-
>>> print job.get_status() ##獲取任務的處理狀態
-
finished
-
>>> step1=q.enqueue(workat,) ##故意不傳遞引數,讓函式執行失敗,則獲取的狀態值是 failed
>>> print step1.get_status()
failed
-
>>> print job.result # 當任務沒有執行的時候返回None,否則返回非空值,如果 函式 hello() 有return 的值,會賦值給result
-
None
-
當我們把worker 監聽程式停止,然後重新發布任務,檢視此時任務的在佇列的狀態,會顯示為 queued
-
>>> job = q.enqueue(hello,'youzan')
-
>>> print job.get_status()
-
queued
-
>>> print job.to_dict() #把job例項轉化成一個字典,我們主要關注狀態。
-
{u'origin': u'default', u'status': u'queued', u'description': u"rq_test.hello('youzan')", u'created_at': '2016-09-06T08:00:40Z', u'enqueued_at': '2016-09-06T08:00:40Z', u'timeout': 180, u'data': '\x80\x02(X\r\x00\x00\x00rq_test.helloq\x01NU\x06youzanq\x02\x85q\x03}q\x04tq\x05.'}
-
>>> job.cancel() # 取消作業,儘管作業已經被執行,也可以取消
-
>>> print job.to_dict()
-
{u'origin': u'default', u'status': u'queued', u'description': u"rq_test.hello('youzan')", u'created_at': '2016-09-06T08:00:40Z', u'enqueued_at': '2016-09-06T08:00:40Z', u'timeout': 180, u'data': '\x80\x02(X\r\x00\x00\x00rq_test.helloq\x01NU\x06youzanq\x02\x85q\x03}q\x04tq\x05.'}
-
>>> print job.get_status()
-
queued
-
>>>
-
>>> job.delete() # 從redis佇列中刪除該作業
-
>>> print job.get_status()
-
None
-
>>> print job.to_dict()
- {u'origin': u'default', u'description': u"rq_test.hello('youzan')", u'created_at': '2016-09-06T08:00:40Z', u'enqueued_at': '2016-09-06T08:00:40Z', u'timeout': 180, u'data': '\x80\x02(X\r\x00\x00\x00rq_test.helloq\x01NU\x06youzanq\x02\x85q\x03}q\x04tq\x05.'}
[1]
[2] 翻譯 - Python RQ Job
[3] 翻譯 - Python RQ Workers
[4] 這位博主寫了很多rq相關的實踐經驗,值得參考。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29371470/viewspace-2124677/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一個輕量級的分散式定時任務排程平臺-Cloudtask分散式Cloud
- 分散式任務排程分散式
- 分散式任務排程系統設計小結分散式
- 分散式排程任務-ElasticJob分散式AST
- 開源分散式任務排程系統就選:DolphinScheduler分散式
- LTS分散式任務排程部署分散式
- 分散式系統架構之構建你的任務排程中心分散式架構
- Easy Scheduler 1.0.2 釋出,分散式工作流任務排程系統分散式
- Aloha:一個分散式任務排程框架分散式框架
- 中介軟體---分散式任務排程---Celery分散式
- 淺談分散式任務排程系統Celery的設計與實現分散式
- micro-job分散式任務排程框架更新分散式框架
- 分散式任務排程平臺XXL-JOB分散式
- 新一代分散式任務排程框架分散式框架
- 基於任務排程的企業級分散式批處理方案分散式
- SpringBoot官方支援任務排程框架,輕量級用起來也挺香!Spring Boot框架
- 在spring boot中3分鐘上手分散式任務排程系統xxl-jobSpring Boot分散式
- Spring Boot Quartz 分散式叢集任務排程實現Spring Bootquartz分散式
- 分散式任務排程平臺XXL-JOB快速搭建教程分散式
- SpringBoot自定義starter開發分散式任務排程實踐Spring Boot分散式
- Python任務排程模組APSchedulerPython
- 詳解BI系統中的任務排程
- 任務排程
- 帶有分散式鎖的Go計劃任務排程器- DEV分散式Godev
- 整合了這個分散式任務排程平臺,真的很爽~~分散式
- 分散式任務排程內的 MySQL 分頁查詢最佳化分散式MySql
- Java 分散式任務排程平臺:PowerJob 快速開始+配置詳解Java分散式
- Airflow 任務排程AI
- Laravel 任務排程Laravel
- LiteOS-任務篇-原始碼分析-任務排程函式原始碼函式
- 系統架構設計之-任務排程系統的設計架構
- OPPO大資料離線任務排程系統OFLOW大資料
- 『學了就忘』Linux系統定時任務 — 89、任務排程工具anacronLinux
- SchedulerX 如何幫助使用者解決分散式任務排程難題?分散式
- 基於Hyperf開發的任務排程系統.支援任務投遞,DAG任務編排(多個任務使用同一個事務).
- Spring 指南(排程任務)Spring
- 開源公開課丨大資料排程系統 Taier 任務排程介紹大資料AI
- go語言實戰課程《Go語言開發分散式任務排程 輕鬆搞定高效能Crontab》——推薦分享Go分散式
- Spark中資源排程和任務排程Spark