php swoole task 踩坑及優化

若是有仔細看過 swoole task 的文檔的話,應該都會注意到這句話html

task 操做的次數必須小於onTask處理速度,若是投遞容量超過處理能力,task會塞滿緩存區,致使worker進程發生阻塞。worker進程將沒法接收新的請求緩存

task 若是阻塞會引起 woker 進程阻塞,形成服務沒法工做,引起問題。swoole

我曾經使用 task 發送服務的鏈路日誌,接收日誌的服務出現bug,形成發送日誌的 task 阻塞,而後服務 gg 的狀況,以後我就對 task 作了一波優化。架構

思路就是使用 swoole channel (https://wiki.swoole.com/wiki/page/647.html)和 swoole user process (https://wiki.swoole.com/wiki/page/390.html)實現一套 task 。測試

使用 channel 接收數據,而後在 user process 消費數據,假如 channel 滿了僅僅會形成 push 數據失敗,並不會引起阻塞,由於是鏈路日誌,是容許丟失的,因此這個方案徹底沒問題。優化

在swoole user process 消費 channel 的策略的僞代碼以下日誌

$sleepTime = 5;
$maxSleepTime = 100;
while (true) {
    $task = $chan->pop();
    if ($task === false) {
        $sleepTime = $sleepTime + 5;
        if ($sleepTime > $maxSleepTime) {
            $sleepTime = $maxSleepTime;
        }
        usleep($sleepTime * 1000);
        continue;
    }
    $sleepTime = 0;
    // 處理數據
}

若是消費到channel的數據,就使用死循環處理數據,由於處理數據過程當中是有其餘操做的,因此並不會佔用大量 cpu。code

若是消費不到數據,就 sleep 5ms,sleep的時間依次累加,直到達到最大值 100ms,達到 cpu 使用率和處理數據實時性的一個平衡,具體平衡點能夠根據本身的業務按需調整。htm

另外,還有使用channel還有一個小坑,往 channel 發送數據使用的 swoole 進程通訊機制(不單單是channel,swoole 使用進程通訊地方基本都有這問題,task 也是),swoole 的進程通訊有個點須要注意一下,那就是超過8k的數據會在磁盤產生臨時文件,並且這個臨時文件 swoole 本身並不會清理,由於這個問題,測試環境的磁盤被這些臨時文件打爆過。進程

怎麼處理這個問題呢?個人思路就是使用gzip壓縮一下數據,這樣能夠解決在個人應用場景中超過8k的數據,可是若是在其餘場景下,即便處理過數據依然超過8k怎麼辦呢?寫個腳本,定時刪吧,好像也沒很好的方法。

更多架構、PHP、GO相關踩坑實踐技巧請關注個人公衆號:PHP架構師

相關文章
相關標籤/搜索