注册
登录

您现在的位置是:首页 > 学无止境

swoole http server 性能优化

木木彡82 2018-08-23 21:40:10 0人围观
swoole http server 性能优化

转载自:https://mp.weixin.qq.com/s?__biz=MzU5MDY4MzY5Mw==&mid=2247483719&idx=1&sn=2802d81c940086ba48205f6def64a3f4&chksm=fe3bca05c94c43133df997e8c295e9280e163ce4e85d5c5adc7c78db257a08b02b9e15c616a0&mpshare=1&scene=1&srcid=0822nFt0G70Zl2EfeeaAGyZr#rd

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

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

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

那么怎么优化呢?

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

启用Http GZIP压缩。压缩可以减小HTML内容的尺寸,有效节省网络带宽,提高响应时间。必须在write/end发送内容之前执行gzip,否则会抛出错误。swoole_http_response->gzip(int level=1);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 分段发送,上线之后效果很明显,耗时监控毛刺少了很多。

有些机智的同学或许会有这个疑问,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_tngx_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 也同样适用。


文章评论

  • 登录后评论

点击排行