我试图测量一个简单的Node.js程序的吞吐量与CouchDB后端使用摇篮作为DB驱动程序。当我对程序加载时,我在30秒内得到以下错误:
EADDRINUSE,地址已被使用
下面是我的程序:
var http = require ('http'),
url = require('url'),
cradle = require('cradle'),
c = new(cradle.Connection)('127.0.0.1',5984,{cache: false, raw: false}),
db = c.database('testdb'),
port=8081;
http.createServer(function(req,res) {
var id = url.parse(req.url).pathname.substring(1);
db.get(id,function(err, doc) {
res.writeHead(200,{'Content-Type': 'application/json'});
res.write(JSON.stringify(doc));
res.end();
});
}).listen(port);
console.log("Server listening on port "+port);
我正在使用一个有50个并发用户的JMeter脚本。平均响应时间为120ms,平均文档大小为3KB。
可以看到,我将Cradle的缓存设置为false。为了进行调查,我查看了等待套接字的数量:它增加到大约4000个,然后崩溃(netstat | grep WAIT | wc -l)
为了测试其他选项,我将缓存设置为true。在这种情况下,程序不会崩溃,但是等待套接字的数量随着时间的推移增加到近10000个。
我还编写了与Java Servlet相同的程序(不包括异步部分),它运行良好,等待套接字的数量不会超过20。
我的问题是:为什么我得到' EADDRINUSE,地址已经在使用'错误?为什么等待套接字的数量如此之高?
注:这是netstat|grep WAIT:
的输出片段tcp4 0 0 localhost.5984 localhost.58926 TIME_WAIT
tcp4 0 0 localhost.5984 localhost.58925 TIME_WAIT
tcp4 0 0 localhost.58924 localhost.5984 TIME_WAIT
tcp4 0 0 localhost.58922 localhost.5984 TIME_WAIT
tcp4 0 0 localhost.5984 localhost.58923 TIME_WAIT
您确定8001上没有僵尸进程吗?
ps aux | grep node
可以帮助
还写了一篇文章来帮助人们开始使用node和couchdb,如果您感兴趣,可以查看http://writings.nunojob.com/2011/09/getting-started-with-nodejs-and-couchdb.html
升级到Cradle 0.5.6。它没有问题。
对问题的推测
等待套接字可能处于CLOSE_WAIT状态。(还有其他状态可以匹配你的grep
,比如TIME_WAIT
。你能确认它是CLOSE_WAIT
而不是其他的吗?)
链接的帖子有一个有用的引用:
RF793说CLOSE_WAIT是TCP/IP堆栈等待本地应用程序释放套接字。因此,它挂起是因为它收到了信息远程主机已启动断开连接并正在关闭其套接字,在什么情况下本地应用程序没有关闭自己的一边。
因此,解决方案可能包括为您的应用程序找到一个bug修复…
。在您的示例中,每个查询有两个连接,一个从JMeter到Node,另一个从Node到CouchDB。JMeter(较老的更成熟的软件)没有正确关闭连接,或者Cradle(较新,较不成熟的软件)没有正确关闭连接。很明显,摇篮最有可能感染这种病毒。(也许这是NodeJS的HTTP库本身,但摇篮似乎是第一个检查的地方。)
我没有一个完整的答案,但希望这些将是有用的线索。我认为地址使用错误是因为没有更多的源地址来进行"传出"连接(即使对于127.0.0.1)。但到目前为止,我不确定为什么CLOSE_WAIT计数在每次试验中都不同。(可能由于整个连接池都关闭了,所以波动很大)要获得更多信息,可以尝试另一个CouchDB客户端库,如request或nano,并比较结果。
请告诉我们你发现了什么,因为它将是伟大的识别和关闭这个潜在的摇篮bug(或bug 某处至少!)。谢谢。