好吧,貌似又是概念上的歧义。
在 2017年12月8日 上午9:47,Zexuan Luo <spacew...@gmail.com> 写道:
>> ngx.thread.spawn是并行的同步,问题例子中的第一种方法是串行
>
> 为什么 ngx.thread.spawn 是并行的同步呢?
>
> 在 2017年12月7日 上午11:22,Sen Han <yunth...@gmail.com> 写道:
>> 当然了,这里只是语言名词的理解和对象不同, 更准确地说:
>>
>> 从系统整体的角度来看它是非阻塞的,但是从这段lua脚本程序的角度来讲是“阻塞”的,
>> 这里更好的词应该是“同步”,既然是同步,就会有些时间消耗,
>> ngx.thread.spawn是并行的同步,问题例子中的第一种方法是串行
>> 同步(只不过在内核协议栈中有一定轻微程度的并行)。
>>
>> 2017-12-07 10:53 GMT+08:00 soul11201 <soul...@gmail.com>:
>>>
>>>
>>> 和第一种段代码效率应该差不多。reader 是非阻塞的。
>>>
>>>
>>> -----
>>> http://blog.soul11201.com
>>>
>>> 在 2017年12月7日 上午8:17,Sen Han <yunth...@gmail.com>写道:
>>>>
>>>> 有一个问题,为什么不直接使用ngx.thread.spawn呢?这样总体能做到真正的异步事件触发,整体延迟会更低,效率更高。
>>>>
>>>> 之前测试过ngx.thread.spawn并发处理成千上万个连接任务都没有问题,效率很棒。
>>>>
>>>>> body = {} k=1
>>>>> for i=1, 10, 1 do
>>>>> local resp = {}
>>>>> for j=1, 3, 1 do
>>>>> local client = http.new()
>>>>> client:connect(某个server)
>>>>> resp[j] = make_request()
>>>>> end
>>>>> for j=0, 2, 1 do --读取数据
>>>>> reader = resp[j].body_reader
>>>>> body[k] = reader()
>>>>> k = k +1
>>>>> end
>>>>> end
>>>>
>>>>
>>>> 即使是例子中的第一个方法,如果其中的一个reader函数很久才会返回一次很小的数据量,它就会成为系统吞吐的短板。
>>>>
>>>> 当然,要控制好总体的请求时间,就需要自己加上严谨的超时处理逻辑了。
>>>>
>>>> All best
>>>>
>>>> 2017-12-06 14:56 GMT+08:00 soul11201 <soul...@gmail.com>:
>>>>>
>>>>> sorry 刚才看错代码了,从理论上分析 第一种 效率更高些。
>>>>>
>>>>> 再补充一点个人的看法。
>>>>>
>>>>>
>>>>> 相比第二个代码,调用发送函数后,后续工作交给内核了。
>>>>>
>>>>> 所以多个发送的请求时间序列上可能出现重叠,这个时候就节省了一部分时间。如果没有,效率并没有提升。
>>>>>
>>>>> 读取数据时候,所用的时间,也会和发送有交叉影响的,有可能你还在发送着中间某个连接的请求,前面请求的响应数据已经准备好在接受缓冲区中等待你去读取。
>>>>>
>>>>> 个人以为,内核的tcp 接受缓冲区跟发送缓冲区 模型是理解你这两段代码问题的关键。系统调用函数,其实一般都是对这两个缓冲区操作。
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> -----
>>>>> http://blog.soul11201.com
>>>>>
>>>>> 在 2017年12月6日 下午2:09,Zexuan Luo <spacew...@gmail.com>写道:
>>>>>>
>>>>>> > 你的意思是认为 在第一种情况下的效率会更高吗? 如果都是串行的方式,那么效率提升在哪里呢 ?
>>>>>>
>>>>>> 对的,我认为第一种效率会更高。
>>>>>>
>>>>>> 我的推理步骤是这样的:
>>>>>> 首先定义两个概念:on-cpu time 和 off-cpu
>>>>>> time。前者是占用CPU的时间,这里简单地当作运行Lua代码的时间;后者是不占用CPU的时间,这里简单地当作网络IO占用的时间。
>>>>>>
>>>>>> 因为:一个请求花费的时间,是花在这个请求上的 on-cpu time + off-cpu time。其中 off-cpu time
>>>>>> 是可以重叠的,比如同时等待多个对端的响应;而 on-cpu time 是独占的,在某一时刻只会运行一个Lua协程。
>>>>>>
>>>>>> 所以:如果要提高效率,在 on-cpu time 不变的情况下,应该增加 off-cpu time
>>>>>> 的重叠率。换句话说,应该同时发起更多的网络请求。
>>>>>>
>>>>>> 当然,以上的推论隐含很多理想假设,有点类似于“真空中的球形鸡”。如果要想知道现实中运行的情况,建议做下火焰图分析。
>>>>>>
>>>>>> > 那请问下多个子请求的执行是是如何达到 那个最长时间的子请求时间为多个子请求执行完成的时间的?
>>>>>>
>>>>>> 那个最长时间的子请求时间为多个子请求执行完成的时间 这个说法值得商榷...
>>>>>>
>>>>>> 如果所有请求的过程中都没有发生yield(没有网络IO,没有sleep,etc.),那么执行过程是这样的:
>>>>>> sr1 start
>>>>>> sr1 end
>>>>>> sr2 start
>>>>>> sr2 end
>>>>>>
>>>>>> 执行时间为 sr1 + sr2
>>>>>>
>>>>>> 如果请求过程中发生了 yield,那么执行过程(简单来说)是这样的:
>>>>>> sr1 start
>>>>>> sr1 yield
>>>>>> sr2 start
>>>>>> sr2 yield
>>>>>> wait_to_resume
>>>>>> sr1 resume
>>>>>> sr1 end
>>>>>> wait_to_resume
>>>>>> sr2 resume
>>>>>> sr2 end
>>>>>>
>>>>>> 执行时间为 sr1_on_cpu + sr2_on_cpu + wait_to_resume。
>>>>>>
>>>>>> 举个例子,如果有两个子请求,一个sleep 0.2 秒,一个 sleep 0.3 秒,除了 sleep,它们什么都不干。
>>>>>> 由于它俩什么都不干,所以 on_cpu 时间都为
>>>>>> 0.第一个请求等待0.2秒后结束,第二个请求等待0.3秒后结束,所以总等待时间为0.2(等待第一个请求)+0.1(等待第二个请求),为
>>>>>> 0.3 秒。
>>>>>> 注意只有在上述例子中,多个子请求执行完成的时间才等于最长的子请求时间。
>>>>>>
>>>>>> 在 2017年12月6日 上午10:51,keke fan <3824...@qq.com> 写道:
>>>>>> > 谢谢回复~
>>>>>> >
>>>>>> > 由于一个 Nginx worker 同时只会运行一个 Lua 协程,所有方式都是串行的,即使子请求也不例外。
>>>>>> > -------
>>>>>> > 你的意思是说,在一个worker里面,在某一个时刻只会运行一个Lua协程,这个是没有疑问的。那请问下多个子请求的执行是是如何达到
>>>>>> > 那个最长时间的子请求时间为多个子请求执行完成的时间的?
>>>>>> >
>>>>>> >
>>>>>> > 个人认为,假定对端 Server 的服务效率跟请求数无关,且网络IO不是瓶颈,那么连续发起多个请求的延迟会比逐个请求更低,效率会更高。
>>>>>> > ----------------
>>>>>> > 你的意思是认为 在第一种情况下的效率会更高吗? 如果都是串行的方式,那么效率提升在哪里呢 ?
>>>>>> >
>>>>>> > 谢谢
>>>>>> >
>>>>>> >
>>>>>> > 在 2017年12月5日星期二 UTC+8下午11:41:46,Zexuan Luo写道:
>>>>>> >>
>>>>>> >> 由于一个 Nginx worker 同时只会运行一个 Lua 协程,所有方式都是串行的,即使子请求也不例外。
>>>>>> >>
>>>>>> >> 个人认为,假定对端 Server 的服务效率跟请求数无关,且网络IO不是瓶颈,那么连续发起多个请求的延迟会比逐个请求更低,效率会更高。
>>>>>> >>
>>>>>> >> 在 2017年12月5日 下午9:08,keke fan <3824...@qq.com> 写道:
>>>>>> >> > 谢谢回复~
>>>>>> >> >
>>>>>> >> > 您的意思是用子请求的方式,这个确实是并行的。
>>>>>> >> >
>>>>>> >> > 不过我们的项目都是纯Lua的,没有location的配置,不能够利用这种子请求中capture到某个location的操作。
>>>>>> >> >
>>>>>> >> >
>>>>>> >> > 另外,能否请您解释下,第二种方式为啥是串行的,用lua-resty-http库发起的请求 是放在新的lua
>>>>>> >> > thread上下文中处理的吧(看代码貌似https://github.com/pintsized/lua-resty-http); 。
>>>>>> >> >
>>>>>> >> >
>>>>>> >> >
>>>>>> >> > 谢谢
>>>>>> >> >
>>>>>> >> > 在 2017年12月5日星期二 UTC+8下午8:57:15,Zhantao Liu写道:
>>>>>> >> >>
>>>>>> >> >> 这两种都是串行的,试试转成并行:
>>>>>> >> >>
>>>>>> >> >> location /real_request/ {
>>>>>> >> >> content_by_lua '
>>>>>> >> >> local rsp1,rsp2,rsp3 = ngx.location.capture_multi{
>>>>>> >> >> {"/proxy1"},
>>>>>> >> >> {"/proxy2"},
>>>>>> >> >> {"/proxy3"}
>>>>>> >> >> }
>>>>>> >> >> ';
>>>>>> >> >> }
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >> location /proxy1 {
>>>>>> >> >> content_by_lua ‘
>>>>>> >> >> local client = http.new()
>>>>>> >> >> client:connect(某个server)
>>>>>> >> >> ngx.say(make_request())
>>>>>> >> >> ';
>>>>>> >> >> }
>>>>>> >> >> location /proxy2 {
>>>>>> >> >> content_by_lua '
>>>>>> >> >> local client = http.new()
>>>>>> >> >> client:connect(某个server)
>>>>>> >> >> ngx.say(make_request())
>>>>>> >> >> ';
>>>>>> >> >> }
>>>>>> >> >> location /proxy3 {
>>>>>> >> >> content_by_lua '
>>>>>> >> >> local client = http.new()
>>>>>> >> >> client:connect(某个server)
>>>>>> >> >> ngx.say(make_request())
>>>>>> >> >> ';
>>>>>> >> >> }
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >> 在 2017年12月5日,下午8:20,keke fan <3824...@qq.com> 写道:
>>>>>> >> >>
>>>>>> >> >> hello:
>>>>>> >> >>
>>>>>> >> >> 在用lua-resty-http库发起对远端的请求时,有这样两种方式:
>>>>>> >> >> 1 每次创建3个客户端进行连接不同的3个server,将每个返回的resp缓存在table中,然后统一进行resp的读取。
>>>>>> >> >> 2 每次只创建1个客户端,进行读取 。
>>>>>> >> >>
>>>>>> >> >> 所需要读取的数据都一样,请问在OR里面会有效率的差异吗?伪代码如下:
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >> 第一种情况:
>>>>>> >> >> body = {} k=1
>>>>>> >> >> for i=1, 10, 1 do
>>>>>> >> >> local resp = {}
>>>>>> >> >> for j=1, 3, 1 do
>>>>>> >> >> local client = http.new()
>>>>>> >> >> client:connect(某个server)
>>>>>> >> >> resp[j] = make_request()
>>>>>> >> >> end
>>>>>> >> >>
>>>>>> >> >> for j=0, 2, 1 do --读取数据
>>>>>> >> >> reader = resp[j].body_reader
>>>>>> >> >> body[k] = reader()
>>>>>> >> >> k = k +1
>>>>>> >> >> end
>>>>>> >> >> end
>>>>>> >> >>
>>>>>> >> >> 第二种情况:
>>>>>> >> >> for i = 1, 30, 1 do
>>>>>> >> >> local client = http.new()
>>>>>> >> >> client:connect(某个server)
>>>>>> >> >> resp[i] = make_request()
>>>>>> >> >> reader = resp[j].body_reader
>>>>>> >> >> body[k] = reader()
>>>>>> >> >> k=k+1
>>>>>> >> >> end
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >> 注意:每次连接都是不同的server,两种情况下需要获取的数据量大小都是一样的。
>>>>>> >> >>
>>>>>> >> >> 请问,这两种情况有效率上的差别吗?第一种情况下,同时开了两个连接,在OR的场景下,效率能否有提高?
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >> --
>>>>>> >> >> --
>>>>>> >> > --
>>>>>> > --
>>>>>> --
>>>>> --
>>>> --
>>> --
>>