龙卷风“错误:[Errno 24]打开的文件太多"错误 [英] Tornado "error: [Errno 24] Too many open files" error

查看:63
本文介绍了龙卷风“错误:[Errno 24]打开的文件太多"错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经与Tornado进行了很多合作,但这是我第一次遇到这种错误.我一直在研究一个非常基本的URL缩短器. URL由另一种应用程序放入数据库中,该应用程序仅从MongoDB存储中读取URL并重定向客户端.编写基本代码后,我针对它设置了一个简单的"Siege"测试,在运行siege(对4个应用程序线程使用siege -c 64 -t 5m -r 1 http://example.com/MKy运行)约30秒钟之后,我开始获得500个响应.在错误日志中查看,我看到了;

I've worked with Tornado quite a bit, but this is the first time I've run into this sort of error. I've been working on a very basic URL shortener. URLs are put into the database by a different application, this one just reads the URLs from a MongoDB store and redirects the clients. After I'd written the basic code I set up a simple 'Siege' test against it, after about 30 seconds of running siege (run with siege -c 64 -t 5m -r 1 http://example.com/MKy against 4 application threads) I started getting 500 responses. Looking in the error log I saw this;

ERROR:root:500 GET /MKy (127.0.0.1) 2.05ms
ERROR:root:Exception in I/O handler for fd 4
Traceback (most recent call last):
  File "/opt/python2.7/lib/python2.7/site-packages/tornado-2.1-py2.7.egg/tornado/ioloop.py", line 309, in start
  File "/opt/python2.7/lib/python2.7/site-packages/tornado-2.1-py2.7.egg/tornado/netutil.py", line 314, in accept_handler
  File "/opt/python2.7/lib/python2.7/socket.py", line 200, in accept
error: [Errno 24] Too many open files
ERROR:root:Uncaught exception GET /MKy (127.0.0.1)
HTTPRequest(protocol='http', host='shortener', method='GET', uri='/MKy', version='HTTP/1.0', remote_ip='127.0.0.1', body='', headers={'Host': 'shortener', 'Accept-Encoding': 'gzip', 'X-Real-Ip': '94.23.155.32', 'X-Forwarded-For': '94.23.155.32', 'Connection': 'close', 'Accept': '*/*', 'User-Agent': 'JoeDog/1.00 [en] (X11; I; Siege 2.66)'})
Traceback (most recent call last):
  File "/opt/python2.7/lib/python2.7/site-packages/tornado-2.1-py2.7.egg/tornado/web.py", line 1040, in wrapper
  File "main.py", line 58, in get
  File "main.py", line 21, in dbmongo
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/connection.py", line 349, in __init__
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/connection.py", line 510, in __find_master
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/connection.py", line 516, in __try_node
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/database.py", line 301, in command
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/collection.py", line 441, in find_one
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/cursor.py", line 539, in loop
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/cursor.py", line 560, in _refresh
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/cursor.py", line 620, in __send_message
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/connection.py", line 735, in _send_message_with_response
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/connection.py", line 591, in __stream
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/connection.py", line 200, in get_stream
  File "/opt/python2.7/lib/python2.7/site-packages/apymongo-0.0.1-py2.7-linux-x86_64.egg/apymongo/connection.py", line 559, in __connect
AutoReconnect: could not connect to [('127.0.0.1', 27017)]

重要(我想);

错误:[错误24]打开的文件太多

error: [Errno 24] Too many open files

代码; (非常简单)

import tornado.ioloop
import tornado.web
import tornado.escape
import apymongo
import time
import sys

#Useful stuff (Connect to Mongo)
class setup(tornado.web.RequestHandler):
    def dbmongo(self):
        if not hasattr(self, '_dbmongo'):
            self._dbmongo = apymongo.Connection("127.0.0.1", 27017)
        return self._dbmongo


#Basic method to lookup URLs from Mongo and redirect accordingly
class expand(setup):
    @tornado.web.asynchronous
    def get(self, url):
        self.mongo = self.dbmongo()

        #Lookup the URL
        cursor = self.mongo.rmgshortlinks.links.find_one({'short':url}, self.direct)

    def direct(self, response):
        if response == None:
            self.send_error(404)
            self.finish()
            return

        link = tornado.escape.url_unescape(response['long'])

        #Bounce the client
        self.write("<!DOCTYPE html><html><head><meta charset=\"UTF-8\" /><meta http-equiv=\"refresh\" content=\"0;URL="+link+"\"</head><body><a href=\""+link+"\">Click Here</a></body></html>")
        self.finish();


#Define the URL routes
application = tornado.web.Application([
    (r"/([a-zA-Z0-9]+)", expand)
])

#Start the server
if __name__ == "__main__":
    listening_port = int(sys.argv[1])

    if listening_port > 0:
        application.listen(listening_port)
        tornado.ioloop.IOLoop.instance().start()
    else:
        sys.stderr.write("No port specified!")

我正在使用的dev服务器具有8个内核和64GB内存,运行RedHat Enterprise Linux 5和Python 2.6.以前,我从未遇到过Tornado/Async Mongo应用程序这类问题.

The dev server I'm using has 8 cores and 64GB memory, running RedHat Enterprise Linux 5 and Python 2.6. I've never had these sorts of issues with Tornado/Async Mongo applications before.

可能有用的信息;

[root@puma ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31374
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31374
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

(打开的文件仅设置为1024,但我认为这已经足够了)

(open files is only set to 1024 but I would have thought that's more than enough)

Tornado/Apymongo是否无法正确关闭连接?这些应用程序位于NGINX后面,但使用HTTP连接,Apymongo应该通过TCP连接,但可能使用套接字.即使这样,它也应该共享/共享连接吗?

Is Tornado/Apymongo not closing the connections properly? The applications sit behind NGINX but connect using HTTP, Apymongo should be connecting via TCP but might be using sockets. Even so it should be sharing/pooling connections shouldn't it?

按照建议,将应用程序移动到我们的其中一台测试服务器上,最大打开文件限制为61440,在围攻运行约30秒后出现相同错误.

As suggested, moved the app onto one of our testing servers with a max open files limit of 61440, same error after about 30 seconds of running in siege.

推荐答案

很简单,为每个请求实例化RequestHandler对象.这意味着您要保存的缓存对象位于RequestHandler(例如,expand)对象上.

Very simple, the RequestHandler object is instantiated for every request. Which means that the cached object that you're saving is on the RequestHandler (e.g. expand) object.

如果要向dbmongo(...)函数添加简单的"print'CREATED!'",您会看到它是在每个GET请求上创建的.

If you were to add a simple "print 'CREATED!'" to the dbmongo(...) function you would see that it's created on every GET request.

您需要做的是将处理程序附加到类对象上,或者根据需要附加全局",尽管最好的情况是将其放在Tornado Application对象上.

What you need to do is attach the handler to the class object, or a "global" as needed, though the best case is to put it on the Tornado Application object.

简单:

class setup(tornado.web.RequestHandler):
    @classmethod
    def dbmongo(cls):
        if not hasattr(cls, '_dbmongo'):
            cls._dbmongo = apymongo.Connection("127.0.0.1", 27017)
        return cls._dbmongo

第二种方法只是使其在文件中成为全局文件:

Second approach is just to make it a global in your file:

dbmongo_connection = None
def dbmongo():
    if not dbmongo_connection:
        dbmongo_connection = apymongo.Connection("127.0.0.1", 27017)
    return dbmongo_connection

这两个都有相同的问题,即如果您有很多想要使用数据库连接的类,则很难共享它.由于数据库是共享实体,因此您可能希望为整个应用程序使用一个实体.

Both of these have the same problem which is that if you have lots of classes that want to use the DB connection, it's harder to share it. Since the DB is a shared entity you probably want one for your whole application.

class MongoMixin(object):
    def mongodb(self):
        if not hasattr(self.application, 'mongodb'):
            self.application.mongodb = apymongo.Connection(self.application.settings.get("mongohost", "127.0.0.1"), 27017)
        return self.application.mongodb

class expand(tornado.web.RequestHandler, MongoMixin):
    def get(self):
       db = self.mongodb()

这篇关于龙卷风“错误:[Errno 24]打开的文件太多"错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆