swoole http server 性能优化

上线了一个基于 swoole http server 的服务之后,发现这个服务的请求耗时监控毛刺十分严重,接口耗时波动比较大,通过一段时间的分析,发现这个服务 response 包十分大,有些 response 包高达1 ~ 2M,甚至更大,这样就很清楚了,由于包太多,致使服务相应波动比较大。php

这里稍微解释下,为何 response 包会致使相应时间波动,这里主要有两个方面的影响,第一是包大会致使 swoole 之间进程通讯更加耗时,并占用更多资源,第二是包大会致使 swoole 的 reactor 线程发包更加耗时,关于 reactor 的解释,摘自react

Swoole的主进程是一个多线程的程序。其中有一组很重要的线程,称之为Reactor线程。它就是真正处理TCP链接,收发数据的线程。 Swoole的主线程在Accept新的链接后,会将这个链接分配给一个固定的Reactor线程,并由这个线程负责监听此socket。在socket可读时读取数据,并进行协议解析,将请求投递到Worker进程。在socket可写时将数据发送给TCP客户端。nginx

那么怎么优化呢?swoole

其实很简单,那就是直接在 swoole 里开启 gzip,这里摘自 swoole 文档网络

启用Http GZIP压缩。压缩能够减少HTML内容的尺寸,有效节省网络带宽,提升响应时间。必须在write/end发送内容以前执行gzip,不然会抛出错误。swoole_http_response->gzip(int $level = 1);$level 压缩等级,范围是1-9,等级越高压缩后的尺寸越小,但CPU消耗更多。默认为1,调用gzip方法后,底层会自动添加Http编码头,PHP代码中不该当再行设置相关Http头多线程

刚开始我是采用这个方式,确实有些效果,可是效果还不是很明显,而后我想到了一个新的方案,就是 http chunk + gzip,这个 swoole 自己是仅提供了chunk的支持,chunk+gzip须要本身实现,实现也很简单架构

swoole_http_response->header('Content-Encoding', "gzip");

    $content = gzencode($content, 6);

    $arr = str_split($content, 1024);

    foreach ($arr as $v) {

        swoole_http_response->write($v);

    }

    swoole_http_response->end();

使用php压缩相应内容,而后使用 swoole_http_response->write 分段发送,上线以后效果很明显,耗时监控毛刺少了不少。socket

有些机智的同窗或许会有这个疑问,swoole http server 通常状况下,会被 nginx 反向代理,nginx 广泛会打开 gzip,那么问题来了,swoole 把数据 gzip 了,nginx 会不会把数据二次压缩。函数

固然不会了,这但是nginx,来,虽然nginx的文档里并无说明gzip不会被二次压缩,可是我在源码里找到了相关逻辑优化

src/http/modules/ngx_http_gzip_filter_module.c,略去无关代码,下面函数调用ngx_http_gzip_ok检测是不是gzip

static ngx_int_t

ngx_http_gunzip_header_filter(ngx_http_request_t *r)

{

    ……

    if (!r->gzip_tested) {

        if (ngx_http_gzip_ok(r) == NGX_OK) {

            return ngx_http_next_header_filter(r);

        }

    } else if (r->gzip_ok) {

        return ngx_http_next_header_filter(r);

    }

    ……

}

src/http/ngx_http_core_module.c,略去无关代码,ngx_http_gzip_ok根据http header检测是不是gzip

ngx_int_t

ngx_http_gzip_ok(ngx_http_request_t *r)

{



    ……

    if (ae->value.len < sizeof("gzip") - 1) {

        return NGX_DECLINED;

    }

    ……

}

从上述两块代码能够看出,nginx 并不会对 gzip 的包二次压缩。

因此,放心大胆的使用吧。

最后,虽然这篇文章,讲的是针对swoole http server 作的一个优化,可是这个思路,对于其余http server 也一样适用。

更多架构、PHP、GO相关踩坑实践技巧请关注个人公众号:PHP架构师

相关文章
相关标签/搜索