介紹
在本方案中,使用celery作為任務分發平臺。對于存入celery的大量任務,能達到以下的要求:
- 任務邏輯相互獨立
- 橫向擴展任務處理能力
- 抽象(抽象的意義在于,化繁為簡) 除業務邏輯以外的 處理過程,將后續代碼編寫的關注點主要放在業務邏輯的實現上
- 鏈式任務觸發
結構
設計方案
任務邏輯封裝
我們將任務邏輯按照約定的格式封裝,并以設置name屬性的方式為任務打上標記,而后通過current_node/default_node確定app 發送的節點。這些準備工作完成后,將任務名稱和任務數據交由celery app進行發送。如此能夠保持發送端的輕量級,使任務更快、更穩定、更無壓力的發送到執行端。
以下是任務的封裝功能偽代碼。
class BaseLogic(object):
logic_name = None
nodes = []
def __init__(self):
if not self.logic_name or not self.nodes:
raise attributeError
def next_node(current_node=None): # 邏輯具有了修改下一個執行節點的能力。
def send_other(self, other_logic_name):
def send_others(self, other_logic_names):
def set(self, key, value):
def get(self, key, default=None):
def die(self):
def __repr__(self):
class SpiderLogic(BaseLogic):
def crawl(self):
def publish(self):
def store(self):
發送器封裝
class App():
def __init__(self, app->celery.app):
self.app = app
def send(self, node_name, data=None): # 發送初始任務。發送任務名稱和傳遞的數據(LogicClass.name, data)
任務處理流程簡述
不同節點的worker會收到屬于本節點的任務。worker提供任務的執行流程。
worker是無狀態的,worker的每次運行會傳入此次運行所需的數據,多次任務運行之間相互不會產生影響。對于無狀態的系統,可以避免考慮數據同步等額外的交互問題。同時根據任務數量級和任務執行所需要的資源的不同,可以對worker進行橫向擴展。
基礎task處理邏輯的封裝功能偽代碼:
class ProcessTask(celery.Task):
"""
worker中實際運行的任務流程封裝
"""
name = None
def __init__(self):
def run(self, data):
logic_ins = logic_factory(data)
self._run(logic_ins)
self.send_next(logic_ins)
self.send_others(logic_ins)
def _run(self, logic_ins):
raise NotImplementedError
def send_next(self, logic_ins):
node_name = logic_ins.next_nodes.pop()
self.send_to_node(node_name)
def send_others(self, logic_ins):
for node_name in logic_ins.other_nodes:
self.send_to_node(node_name)
def send_to_node(self, node_name):
class CrawlProcessTask(ProcessTask):
name = 'crawl'
def _run(self, logic_ins):
logic_ins.crawl()
收到任務的名稱以后,worker會通過 工廠方法 根據任務名稱實例化對應的類,并且按照worker既定的執行流程,執行對應的業務邏輯。
執行完成后,按照logic class 既定的順序,自動觸發下一個流程。當然如果需要將數據進行鏈式處理,那么在邏輯類中,通過定義other_logics,數據也會發送到對應節點開始新的流程。
總結
任務邏輯相互獨立的意義在于,當一個任務需要調整邏輯時,會自然而然的將修改鎖定在獨立的代碼塊中,也就是最小化此次修改的影響范圍。所以我們將任務相互獨立的抽象成不同的邏輯類。而當任務相互獨立以后,我們需要一個統一的任務運行機制,并且此機制希望對于任務毫無干預,也就是機制不關注運行任務的內容是什么,而是關注運行任務的流程。所以我們對于任務運行設計了一套流程。
在流程中,我們將任務封裝成為一個個的類,在類中定義好業務邏輯以及處理節點的順序。類通過一個統一的入口進入流程處理。同時,通過這個順序,被封裝后的celery app 可以找到首個接收的worker 節點,然后通過celery的分布式任務分發能力,進行任務的分發。
同時在類中設置鏈式處理邏輯,解除單個任務之間的壁壘,將任務鏈條串起來,解決任務之間數據交互的問題。
故此,我們將業務代碼抽離出任務分發流程,任務相互獨立,同時提供數據傳遞的方案,保證任務流程的正常執行。同時通過worker節點的無狀態,以及celery節點的擴容能力,使得當有大量任務產生的時候,能夠對任意任務節點數量進行橫向擴展。