关于openresty 调用io.popen在压力测试中报错的问题

329 views
Skip to first unread message

wgm.china

unread,
Mar 13, 2013, 9:49:31 AM3/13/13
to openresty
大家好!
我在用openresty通过io.popen调用linux命令,在功能测试的时候没有问题,在开始用压力测试loadrunner压30个并发的时候,就开始在nginx errlog中看到报错了。
具体的报错信息:
[error] 1802#0: *46160 lua entry thread aborted: runtime error: /usr/local/lua/hbds_upload.lua:0: Interrupted system call
 
具体的调用代码:local popen =io.popen(gcs_upload_command)
 
gcs_upload_command 是一个用C写的上传文件的接口命令。
不知道是怎么回事,是不是需要优化?
 
 
2013-03-13

wgm.china

agentzh

unread,
Mar 13, 2013, 2:58:33 PM3/13/13
to open...@googlegroups.com
Hello!

2013/3/13 wgm.china:
> 大家好!
> 我在用openresty通过io.popen调用linux命令,在功能测试的时候没有问题,在开始用压力测试loadrunner压30个并发的时候,就开始在nginx
> errlog中看到报错了。
> 具体的报错信息:
> [error] 1802#0: *46160 lua entry thread aborted: runtime error:
> /usr/local/lua/hbds_upload.lua:0: Interrupted system call
>
> 具体的调用代码:local popen =io.popen(gcs_upload_command)
>

这个问题先前在 openresty 邮件列表中有过专门的讨论,你可以参考一下:

https://groups.google.com/group/openresty/browse_thread/thread/abd0fbfa087bea75/e89acf6eeee3eec4

引用一下那里的原文:“io.popen 确实创建了新的 sh 子进程,而当 sh
子进程退出时,便会自动向它的父进程,也就是调用 io.popen 的 nginx worker 进程发送 SIGCHLD 信号。而如果此时
nginx 正阻塞在 io.read() 发起的 read 系统调用上时,则该系统调用就会被中断,并返回错误“Interrupted
system call”. 一个直接的解决办法是,总是显式地调用 io.close() 方法关闭当前的 pipe 文件句柄”

特别地,io.popen 这样的调用总是阻塞的,这意味着在你的 shell 命令执行时,你当前的 nginx worker 进程只能处理 1
个并发。所以要慎用。

Best regards,
-agentzh

wgm.china

unread,
Mar 14, 2013, 10:12:06 AM3/14/13
to openresty
    我测试了增加io.close()还是有问题,压力大一点就还是会报错,不过报错已经少很多了,大概在2%的错误率。
看春哥准备增加“我有计划自己在 ngx_lua 中以非阻塞方式重新实现 io.popen 以及对应的 io.read/io.write
方法”不知道有没有做?该怎么调用?
 
2013-03-14

wgm.china

发件人:agentzh
发送时间:2013-03-14 02:58
主题:Re: [openresty] 关于openresty 调用io.popen在压力测试中报错的问题
收件人:"openresty"<open...@googlegroups.com>
抄送:
 
--  
--  
邮件自: 列表“openresty”,专用于技术讨论! 
发言: 请发邮件到 open...@googlegroups.com 
退订: 请发邮件至 openresty+...@googlegroups.com 
 
---  
您收到此邮件是因为您订阅了 Google 网上论坛的“openresty”论坛。 
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 openresty+...@googlegroups.com。 
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。 
 
 

agentzh

unread,
Mar 15, 2013, 2:43:21 PM3/15/13
to open...@googlegroups.com
Hello!

2013/3/14 wgm.china:
> 我测试了增加io.close()还是有问题,压力大一点就还是会报错,不过报错已经少很多了,大概在2%的错误率。

一般地,你要确保 io.close() 调用和你的 io.pipe() 调用之间没有 I/O 操作(或者其他的系统调用)。

如果仍会看到错误,请提供一个能复现问题的最小化的 Lua 代码用例 :)

> 看春哥准备增加“我有计划自己在 ngx_lua 中以非阻塞方式重新实现 io.popen 以及对应的 io.read/io.write
> 方法”不知道有没有做?该怎么调用?
>

这仍然是一个 TODO :) 我抽时间实现一下哈,呵呵。你有兴趣实现的话,也欢迎提供补丁 :)

Best regards,
-agentzh

wgm.china

unread,
Mar 15, 2013, 9:08:24 PM3/15/13
to openresty
我也想做点贡献,不过技术能力有限,还一直关注openresty增加websocket.
 
2013-03-16

wgm.china

发件人:agentzh
发送时间:2013-03-16 02:43
主题:Re: Re: [openresty] 关于openresty 调用io.popen在压力测试中报错的问题
收件人:"openresty"<open...@googlegroups.com>
抄送:
 

junwei shi

unread,
Mar 21, 2013, 10:35:42 PM3/21/13
to open...@googlegroups.com
春哥,最近我在学习ngx_lua
我也想通过实际的开发来加深对ngx_lua的理解,所以我有兴趣抽时间来实现一个非阻塞的popen
我现在大概的思路是:
1.重新实现io.popen,把打开的文件指针对应句柄设置为非阻塞
2.重新实现io.read. 如果文件不可读(返回EAGAIN/EWOULDBLOCK等),把相应的回调函数注册到nginx的事件模型里,并调用lua_yield放弃执行权。
3.回调函数被回调:读取内容,并放到lua的栈里,并重新唤醒lua协程。(如cosocket类似的思想)

由于popen会fork一个新的进程,所以大量并发调用非阻塞版本的popen,也不是一个好主意,所以计划会引入一个类似队列的缓冲区的实现;如超过最大的进程数,后续的popen调用会放到队列里,如果步骤3的callback完成了一个读操作以后,则检查队列是否为空,然后.....


春哥看看上面的想法是否合理..... :) 
Reply all
Reply to author
Forward
0 new messages