利用openresty来优化php-fpm的长轮询

    对于长轮询场景是比较常见的,客户端同步的不断的在同步请求,而服务端根据请求来决定是否响应或者hold请求以继续检查数据.

    由于php-fpm是单进程单线程的,一个进程同时只能处理一个请求,所以对于这种长轮询的场景,需要启动特别多的php-fpm进程来应对高的并发,这是特别浪费资源的,因为大部分请求都是hold在服务器上。

    现在我们用openresty来轮询php-fpm,php-fpm会很快的处理完成,不会hold住,减少了php-fpm的压力,配置文件如下:

location ~ /longpolling(/.*) {
                content_by_lua_block {
                        local request_uri_without_args = ngx.re.sub(ngx.var.request_uri, "\\?.*", "")
                        request_uri_without_args = ngx.re.gsub(request_uri_without_args,"/longpolling","")
                        local url = {request_uri_without_args}
                        local args = ngx.req.get_uri_args()
                        local query = ngx.encode_args(args)
                        if query ~= "" then
                                url[#url + 1] = "?"
                                url[#url + 1] = query
                        end
                        url = table.concat(url)
                        for i = 1, 3 do
                                local sleep = 1
                                local res = ngx.location.capture(url)
                                for k, v in pairs(res.header) do
                                        if type(v) == "table" then
                                                if k == 'sleep' and v == 0 then
                                                        ngx.header[k] = table.concat(v, ",")
                                                        sleep = table.concat(v, ",")
                                                end
                                        else
                                                if k == "sleep" and v == "0" then
                                                        ngx.header[k] = v
                                                        sleep = v
                                               end
                                        end
                                end
                                if sleep == 1 then
                                        ngx.sleep(1)
                                else
                                        ngx.say(res.body)
                                        break
                                end

                        end
                }
        }

    

    将url中以”longpolling”开始的请求转换为长轮询.比如:/longpolling/aa 实际访问是/aa. 长轮询总共时间是3秒,每次停止一秒,根据php-fpm响应头sleep来决定是否输出还是继续轮询.PHP代码如下.

  

<?php
header('Content-type: application/json');
$time = $_GET["time"];
$data = get_new_data($time);
if ( $data ){
        header('sleep:0');
        echo json_encode(array("data"=>$data));
}else{
        echo json_encode(array("data"=>""));
}

 这样我们就做了一个相对通用的仅支持get请求的优化接口。  

此条目发表在 好文推荐, 网站开发, 网站架构 分类目录,贴了 标签。将固定链接加入收藏夹。

评论功能已关闭。