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架构师

相关文章
相关标签/搜索