ngx.location.capture_multi 相较 ngx.location.capture 并没有做到并行与优化

129 views
Skip to first unread message

阮新余

unread,
Aug 6, 2019, 3:29:30 AM8/6/19
to openresty
背景:
 我们工作环境中使用了,openresty , 在一次代码优化中有人提出使用capture_multi 代替 capture 可以做到并行调用子查询 https://github.com/openresty/lua-nginx-module#ngxlocationcapture_multi。我提出质疑并且查看openresty 源码,然后写了一个demo做为佐证。



具体代码:

#user  nobody;
worker_processes  3;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

                location ~ \.html {
       # lua_code_cache off;
              content_by_lua_block {
                    --ngx.print("{'errno':9001}")
local t1 = ngx.now()
        res1, res2, res3, res4, res5, res6 = ngx.location.capture_multi{
                 { "/bar", { method = ngx.HTTP_POST, body = "hello" } },
                 { "/bar2", { method = ngx.HTTP_POST, body = "hello" } },
                 { "/bar3", { method = ngx.HTTP_POST, body = "hello" } },
                 { "/bar4", { method = ngx.HTTP_POST, body = "hello" } },
                 { "/bar5", { method = ngx.HTTP_POST, body = "hello" } },
                 { "/bar", { method = ngx.HTTP_POST, body = "hello" } },
         }
--res1 = ngx.location.capture(
--     '/bar',
--     { method = ngx.HTTP_POST, body = 'hello' }
-- )
--res2 = ngx.location.capture(
--     '/bar2',
--     { method = ngx.HTTP_POST, body = 'hello' }
-- )
--res4 = ngx.location.capture(
--     '/bar4',
--     { method = ngx.HTTP_POST, body = 'hello' }
-- )
--res3 = ngx.location.capture(
--     '/bar3',
--     { method = ngx.HTTP_POST, body = 'hello' }
-- )
--res5 = ngx.location.capture(
--     '/bar5',
--     { method = ngx.HTTP_POST, body = 'hello' }
-- )
--res6 = ngx.location.capture(
--     '/bar',
--     { method = ngx.HTTP_POST, body = 'hello' }
-- )

local t2 = ngx.now()
ngx.print('--t1----'..t2..'----') -- 输出1487053211.321,1487053211.321
        ngx.print("<br>")
ngx.print('--t2----'..t2..'----') -- 输出1487053211.321,1487053211.321
        ngx.print("<br>")
ngx.print('------'..t2-t1..'----') -- 输出1487053211.321,1487053211.321
        ngx.print("<br>")
        ngx.print(res1.body)
        ngx.print("----------")
        ngx.print("<br>")
        ngx.print(res2.body)
        ngx.print("----------")
        ngx.print("<br>")
        ngx.print(res3.body)
        ngx.print("----------")
        ngx.print("<br>")
        ngx.print(res4.body)
        ngx.print("----------")
        ngx.print("<br>")
        ngx.print(res5.body)
        ngx.print("----------")
        ngx.print("<br>")
        --ngx.print(res6.body)
        ngx.print("----------")
        ngx.print("<br>")
return 
                 }   
        } #error_page  404              /404.html;

        location /bar {
            content_by_lua_block {
       -- ngx.sleep(1)
        --os.execute("sleep " .. 1)
        local x = 0
        for i = 1, 100000000 do
        --for i = 1, 10000000000 do
            x = x + i
        end
        ngx.say("ok")
    }
         }

        location /bar2 {
            content_by_lua_block {
        --ngx.sleep(1)
        --os.execute("sleep " .. 1)
        local x = 0
        --for i = 1, 10000 do
        for i = 1, 100000000 do
        --for i = 1, 10000000000 do
            x = x + i
        end
        ngx.say("ok2")
    }
         }

        location /bar3 {
            content_by_lua_block {
        --ngx.sleep(1)
        local x = 0
        --for i = 1, 10000 do
        for i = 1, 100000000 do
        --for i = 1, 10000000000 do
            x = x + i
        end
        ngx.say("ok3")
    }
         }

        location /bar4 {
            content_by_lua_block {
        --ngx.sleep(1)
        --os.execute("sleep " .. 1)
        local x = 0
        --for i = 1, 10000 do
        for i = 1, 100000000 do
        --for i = 1, 10000000000 do
            x = x + i
        end
        ngx.say("ok4")
}
         }

        location /bar5 {
            content_by_lua_block {
        --ngx.sleep(1)
        --os.execute("sleep " .. 1)
        local x = 0
        --for i = 1, 10000 do
        for i = 1, 100000000 do
        --for i = 1, 10000000000 do
            x = x + i
        end
        ngx.say("ok5")
    }
         }
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

结果:
发现调用耗时没有变化, 并且nginx work进程是单线程的,capture_multi,将subrequest 请求都交由当前进程执行ngx_http_lua_post_subrequest 方法,因此优化有限,lua只是通过携程做了一点点优化吧,但是当子查询做纯粹的计算的时候,根本达不到并发效果。

我的实验过程是否合理???麻烦大神指教

wd

unread,
Aug 6, 2019, 4:44:15 AM8/6/19
to open...@googlegroups.com
hi,

看了一下没看到你是怎么得出没什么效果的,我看文档的意思是,使用 multi 的执行时间会是子请求里面最长的那个,如果不用 multi 的话,那按说应该是所有时间的和。你有计算过这个时间吗?

--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html
---
您收到此邮件是因为您订阅了Google网上论坛上的“openresty”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到openresty+...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/openresty/e779ec16-29e7-4e2e-9281-c2081a5a72f4%40googlegroups.com

GoldenMountain

unread,
Aug 6, 2019, 5:27:11 AM8/6/19
to openresty
我计算过时间通过浏览器查看的耗时,单个的串行的调用 capture 与 一次调用capture_multi 是一样的,你可以看我conf的配置。
订阅: 请发空白邮件到 open...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 open...@googlegroups.com

归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html
---
您收到此邮件是因为您订阅了Google网上论坛上的“openresty”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到openresty+unsubscribe@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/openresty/e779ec16-29e7-4e2e-9281-c2081a5a72f4%40googlegroups.com

GoldenMountain

unread,
Aug 6, 2019, 5:29:54 AM8/6/19
to openresty
并且我查看过源码,和我实验的结果一致,就是capture_multi 没有起到优化的作用

tokers

unread,
Aug 6, 2019, 5:32:11 AM8/6/19
to openresty
Hello!

如果子请求都是计算型的任务,意义就不大了,毕竟 Nginx 每个进程只有主线程在执行事件循环处理请求。如果子请求完成一些 I/O 操作,那 caputre_multi 应该会有效果的。

GoldenMountain

unread,
Aug 6, 2019, 5:37:09 AM8/6/19
to openresty
十分感谢,我也在猜想,openresty 使用协程对一些操作进行了挂起,但是具体的IO 类型我等一下做一些实验包括网络IO,与文件IO看一下,我再conf中试过用ngx.sleep 与 os.execute("sleep " .. n) 做过实验,想必如果需要做IO也必须是openresty 做的封装。

GoldenMountain

unread,
Aug 7, 2019, 2:52:17 AM8/7/19
to openresty
我通过子查询改用proxy   upstream的方式调用,并且将每一个upstream设置一个独立的端口,用http_load 进行压测。效果如下:


single proxy 

3026 fetches, 1021 max parallel, 572437 bytes, in 10.0008 seconds
189.173 mean bytes/connection
302.574 fetches/sec, 57238.9 bytes/sec
msecs/connect: 269.022 mean, 3020.23 max, 4.067 min
msecs/first-response: 1559.44 mean, 9401.86 max, 3.003 min
2396 bad byte counts
HTTP response codes:
  code 200 -- 1925


multi proxy
 4065 fetches, 1021 max parallel, 681905 bytes, in 10.0001 seconds
167.75 mean bytes/connection
406.495 fetches/sec, 68189.7 bytes/sec
msecs/connect: 117.222 mean, 3047.4 max, 4.061 min
msecs/first-response: 766.097 mean, 9776.42 max, 3.814 min
3196 bad byte counts
HTTP response codes:
  code 200 -- 3077

同样的请求未拆分成proxy upstream时:

single 
2867 fetches, 1021 max parallel, 344944 bytes, in 10.0002 seconds
120.315 mean bytes/connection
286.695 fetches/sec, 34493.8 bytes/sec
msecs/connect: 180.252 mean, 3042.2 max, 4.31 min
msecs/first-response: 1162.6 mean, 9417.37 max, 3.391 min
1341 bad byte counts
HTTP response codes:
  code 200 -- 1940

multi 
2624 fetches, 1021 max parallel, 276846 bytes, in 10.0002 seconds
105.505 mean bytes/connection
262.395 fetches/sec, 27684 bytes/sec
msecs/connect: 821.346 mean, 4308.39 max, 4.281 min
msecs/first-response: 1086.87 mean, 7551.03 max, 40.953 min
1387 bad byte counts
HTTP response codes:
  code 200 -- 1558


由此可以看出拆分出 多个upstream(端口) 比 同一端口使用子查询效果要好,并且多个upstream中使用multi_capture 具有优化的效果,同一端口使用并且子查询的计算型操作较多,multi_capture优化效果不大。
Reply all
Reply to author
Forward
0 new messages