【问题标题】:Tornado [Errno 24] Too many open files [duplicate]Tornado [Errno 24]打开的文件太多[重复]
【发布时间】:2014-01-02 23:51:51
【问题描述】:

我们在 RedHat 操作系统上运行 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

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

我们的 Tornado 代码如下:

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”状态。

我们的 Tornado 脚本有问题吗?我们认为我们的超时功能无法正常工作,但就我们目前的研究而言,一切似乎都正常。

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

提前致谢,

【问题讨论】:

  • @CDspace 我们已经阅读了它,但无法将答案与我们的场景融为一体。看起来我们的实现中缺少其他东西
  • 只是为了指出这个问题不是重复的。 Ben 的回答正是解决了这个问题。

标签: python tornado


【解决方案1】:

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

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

【讨论】:

  • 嗨,Ben,感谢您的回答,我们将尝试设置一个 nginx 来查看它的运行情况。作为空闲连接问题,我们在实现中设置的 50 毫秒超时不应该已经处理了吗?
  • 不,空闲连接在不阻塞 IOLoop 的情况下保持活动状态(这毕竟是点),所以阻塞阈值在这里不适用。
  • 我明白了。是否有某种方法可以仅使用 Tornado 本身来关闭这些空闲连接?使用 nginx 作为解决方案很好,我们只是想知道我们是否可以通过 Tornado 解决这个问题。
  • 您可以通过将 no_keep_alive=True 传递给 HTTPServer 构造函数(或 Application.listen)来完全关闭连接重用
  • 我花了很长时间才回复这个问题,但感谢 Ben 的回答。我们在Tornado前面架了一个Nginx,问题就解决了。
猜你喜欢
  • 2020-03-07
  • 1970-01-01
  • 1970-01-01
  • 2016-04-21
  • 1970-01-01
  • 1970-01-01
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多