如果有仔細看過 swoole task 的文檔的話,應該都會注意到這句話
task操作的次數(shù)必須小于onTask處理速度,如果投遞容量超過處理能力,task會塞滿緩存區(qū),導致worker進程發(fā)生阻塞。
worker進程將無法接收新的請求? ? ? ? ? ? ? ? ? ? ? ? ? ? (推薦學習: swoole視頻教程)
task 如果阻塞會引發(fā) woker 進程阻塞,造成服務無法工作,引發(fā)問題。
我曾經使用 task 發(fā)送服務的鏈路日志,接收日志的服務出現(xiàn)bug,造成發(fā)送日志的 task 阻塞,然后服務 gg 的情況,之后我就對 task 做了一波優(yōu)化。
思路就是使用 swoole channel 和 swoole user process 實現(xiàn)一套 task 。
使用 channel 接收數(shù)據,然后在 user process 消費數(shù)據,假如 channel 滿了僅僅會造成 push 數(shù)據失敗,并不會引發(fā)阻塞,因為是鏈路日志,是允許丟失的,所以這個方案完全沒問題。
在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; ????//?處理數(shù)據 }
如果消費到channel的數(shù)據,就使用死循環(huán)處理數(shù)據,因為處理數(shù)據過程中是有其他操作的,所以并不會占用大量 cpu。
如果消費不到數(shù)據,就 sleep 5ms,sleep的時間依次累加,直到達到最大值 100ms,達到 cpu 使用率和處理數(shù)據實時性的一個平衡,具體平衡點可以根據自己的業(yè)務按需調整。