2010-08-18 15 views
9

一個工人考慮一個PHP的Web應用程序,其目的是接受用戶請求啓動通用異步作業,然後創建工作進程/線程來運行作業。作業不是CPU或內存密集型的,但預計會經常阻止I/O調用。每秒不應該有一兩個工作要開始,但由於運行時間較長,可能會有很多工作同時運行。與PHP的異步處理 - 每個作業

因此,這是最重要的是作業並行運行。此外,每個作業必須由負責殺雄工人,對用戶請求中止工人管理器守護進程進行監測等

什麼是去實現一個系統,如最好的方法?我可以看到:

  1. 從經理分叉工人 - 這似乎是最低級別的選項,我必須自己實施監控系統。 Apache是​​Web服務器,所以看起來這個選項需要任何PHP工作者通過FastCGI啓動。
  2. 使用某種類型的工作/消息隊列。 (gearman,beanstalkd,RabbitMQ等) - 起初,這似乎是一個明顯的選擇。經過一番研究,我對所有選項都有些困惑。例如,Gearman看起來就是專爲大型分佈式系統設計的,其中有一個固定的工作人員池......所以我不知道我需要的是否合適(每個工作一個工人)。

回答

8

那麼,如果你在Linux上,你可以使用pcntl_fork關閉孩子。 「主人」然後看着孩子們。每個孩子完成其任務,然後正常存在。

就個人而言,我實現我從來沒有需要一個消息隊列。我只是在帶有鎖的「主」中使用一個數組。當一個孩子找到一份工作時,它會寫一個帶有作業ID號碼的鎖定文件。主人然後會等到那個孩子退出。如果在孩子退出後仍然存在鎖定文件,那麼我知道任務未完成,並重新啓動具有相同作業的孩子(刪除鎖定文件後)。根據您的情況,您可以在簡單的數據庫表中實施隊列。在表格中插入作業,並每隔30或60秒查看一次主表中的表格以查找新作業。然後,只有在孩子完成後(並且孩子移除鎖定文件),才從表格中刪除它們。如果您一次運行多個「主」,但是您可以實現一個全局「主PID文件」來檢測和防止多個實例,這會產生問題...

而且我不會建議使用FastCGI 。由於環境意味着持續存在,它可能會導致一些非常模糊的問題。相反,使用CGI如果你必須有它的網絡界面,但理想情況下使用CLI應用程序(deamon)。要與來自其他進程的主設備進行交互,您可以使用套接字進行TCP通信,也可以創建一個用於通信的套接字()。

至於檢測工作人員,你可以實施一個「心跳」系統,孩子每隔幾秒鐘向主進程發出SIG_USR1。那麼如果你兩次或三次沒有收到孩子的消息,它可能會被掛起。但事實是,因爲PHP是不是多線程的,你不能,如果一個孩子被掛起或者告訴我們,如果它只是一個阻塞等待資源(如數據庫調用)......至於實施的「心臟拍」 ,你可以使用tick function自動化心跳(但請記住,阻止呼叫仍然不會執行)...

+0

謝謝。我現在已經做了幾次,而且它真的很好。那麼,如果您的使用案例與系統的侷限性一致(IPC相當昂貴,等等),我應該說它工作得很好。如果它們沒有很好地對齊,那麼應該使用真正的線程實現和除PHP以外的語言...... – ircmaxell 2010-08-18 14:49:36

+2

但是,請仔細閱讀'pcntl_fork()'。我在父進程和子進程之間以奇怪的方式共享數據庫連接時遇到了問題。如果某些PECL擴展共享類似的怪癖,我不會感到驚訝。我會迴避在PHP中分叉,並通過'exec()'等產生單獨的進程,只是爲了保持簡單 – 2010-08-18 14:52:03

+0

好吧,我明確地重新打開孩子分支後的所有連接,因爲這個原因。分叉是沒有什麼可怕的(我經常使用它)。但是由於沒有關於這個主題的大量文檔,這是一個很多的試驗和錯誤。通過'exec'執行的問題是,它使通信和監控變得更加困難(因爲一個'exec'被阻塞,而另外兩個很難獲得非阻塞'exec'調用的進程ID(一個調用在末尾加上'&...))... – ircmaxell 2010-08-18 14:57:38

1

,而你做了許多工作與pcntl_fork異步運行一個任務,否則您將創建持久性查詢每一個(或多個)秒,仔細由於CPU消耗較高,因此無法重新分配內存,因此可能會掛起處理內存,我認爲可以使用Gearman完全構建最佳選擇,也可以嘗試使用IronWorker等雲工作者。