Tornado [Errno 24]太多打开的文件

时间:2014-01-02 23:51:52

标签: python tornado

我们在RedHat OS上运行Tornado 3.0服务并收到以下错误:

[E 140102 17:07:37 ioloop:660] Exception in I/O handler for fd 11
    Traceback (most recent call last):
      File "/usr/local/lib/python2.7/dist-packages/tornado/ioloop.py", line 653, in start
        self._handlers[fd](fd, events)
      File "/usr/local/lib/python2.7/dist-packages/tornado/stack_context.py", line 241, in wrapped
        callback(*args, **kwargs)
      File "/usr/local/lib/python2.7/dist-packages/tornado/netutil.py", line 136, in accept_handler
        connection, address = sock.accept()
      File "/usr/lib/python2.7/socket.py", line 202, in accept
    error: [Errno 24] Too many open files

但我们无法弄清楚这意味着什么。

我们的龙卷风代码如下:

import sys
from tornado.ioloop import IOLoop
from tornado.options import parse_command_line, define, options
from tornado.httpserver import HTTPServer
from tornado.netutil import bind_sockets
import tornado
sys.path.append("..")

from tornado.web import  RequestHandler, Application
from shared.bootstrap import *
from time import time
from clients import ClientFactory

from shared.configuration   import Config
from shared.logger          import Logger

from algorithms.neighborhood.application import NeighborhoodApplication
import traceback

define('port', default=8000, help="Run on the given port", type=int)
define('debug', default=True, help="Run application in debug mode", type=bool)

class WService(RequestHandler):

    _clients = {}

    def prepare(self):
        self._start_time = time()
        RequestHandler.prepare(self)

    def get(self, algorithm = None):

        self.add_header('Content-type', 'application/json')

        response = {'skus' : []}

        algorithm = 'neighborhood' if not algorithm else algorithm

        try:
            if not algorithm in self._clients:
                self._clients[algorithm] = ClientFactory.get_instance(algorithm)

            arguments = self.get_arguments_by_client(self._clients[algorithm].get_expected_arguments())

            response['skus'] = app.get_manager().make_recommendations(arguments)
            self.write(response)

        except Exception as err:
            self.write(response)
            error("Erro: " + str(err))

    def get_arguments_by_client(self, expected_arguments):
        arguments = {}
        for key in expected_arguments:
            arguments[key] = self.get_argument(key, expected_arguments[key])

        return arguments

    def on_connection_close(self):
        self.finish({'skus':[]})
        RequestHandler.on_connection_close(self)

    def on_finish(self):
        response_time = 1000.0 *(time() - self._start_time)
        log("%d %s %.2fms" % (self.get_status(), self._request_summary(), response_time))
        RequestHandler.on_finish(self)

def handling_exception(signal, frame):
    error('IOLoop blocked for %s seconds in\n%s\n\n' % ( io_loop._blocking_signal_threshold, ''.join(traceback.format_stack(frame)[-3:])))

if __name__ == "__main__":

    configuration = Config()
    Logger.configure(configuration.get_configs('logger'))

    app = NeighborhoodApplication({
                                   'application': configuration.get_configs('neighborhood'),
                                   'couchbase':   configuration.get_configs('couchbase'),
                                   'stock':       configuration.get_configs('stock')
                                   })
    app.run()
    log("Neighborhood Matrices successfully created...")
    log("Initiating Tornado Service...")

    parse_command_line()

    application = Application([
                               (r'/(favicon.ico)', tornado.web.StaticFileHandler, {"path": "./images/"}),
                               (r"/(.*)", WService)
                               ], **{'debug':options.debug, 'x-headers' : True})

    sockets = bind_sockets(options.port, backlog=1024)
    server = HTTPServer(application)
    server.add_sockets(sockets)

    io_loop = IOLoop.instance()
    io_loop.set_blocking_signal_threshold(.05, handling_exception)
    io_loop.start()

这是一个非常基本的脚本,基本上它获取了URL,在make_recommendation函数中处理它并发回响应。

我们尝试通过io_loop.set_blocking_signal_threshold函数设置50毫秒的龙卷风超时,因为有时URL的处理可能需要很长时间。

系统每分钟接收大约8000个请求,它工作正常约30分钟,但之后开始抛出“太多文件错误”并崩溃。一般来说,请求大约需要20毫秒来处理,但是当错误开始发生时,消耗的时间会突然增加到几秒钟。

我们试图查看端口8000有多少连接,并且它有几个打开的连接都具有“ESTABLISHED”状态。

我们的龙卷风脚本有什么问题吗?我们认为我们的超时功能无法正常工作,但到目前为止我们所研究的一切似乎都没问题。

如果您需要更多信息,请告诉我。

提前致谢,

1 个答案:

答案 0 :(得分:13)

许多Linux发行版的每个进程的打开文件数量非常低(例如250)。你可以使用" ulimit -n"查看系统上的当前值(确保在与tornado服务器运行相同的环境中发出此命令)。要提高限制,您可以使用ulimit命令或修改/etc/security/limits.conf(尝试将其设置为50000)。

Tornado的HTTP服务器(从3.2版开始)没有关闭Web浏览器打开的连接,因此空闲连接可能会随着时间的推移而累积。这就是为什么建议在Tornado服务器前使用像nginx或haproxy这样的代理的原因之一;这些服务器对这个和其他潜在的DoS问题更加强硬。