打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
python

This question already has an answer here:

We are running a Tornado 3.0 service on a RedHat OS and getting the following error:

[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

But we couldn't figure out what that means.

Our Tornado code is as follows:

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()

It's a very basic script, basically it gets the URL, process it in the make_recommendation function and sends back the response.

We've tried to set a tornado timeout of 50 ms through the io_loop.set_blocking_signal_threshold function as sometimes the processing of the URL might take this long.

The system receives around 8000 requests per minute and it worked fine for about 30 minutes, but after that it started throwing the "too many files error" and broke down. On general the requests were taking about 20 ms to get processed but when the error started happening the time consumed increased to seconds, all of a sudden.

We tried to see how many connections the port 8000 had and it had several open connections all with the "ESTABLISHED" status.

Is there something wrong in our Tornado script? We believe our timeout function is not working properly, but for what we've researched so far everything seems to be ok.

If you need more info please let me know.

Thanks in advance,

asked Jan 2 at 23:51
Will
15829
 
@CDspace We read it already but couldn't assimilate the answer with our scenario. It looks like something else is missing in our implementation –  Will Jan 3 at 0:22
add comment

marked as duplicate by Jake King, David, Interrobang, Sverri M. Olsen, Mitch Dempsey Jan 4 at 0:16

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

1 Answer

Many linux distributions ship with very low limits (e.g. 250) for the number of open files per process. You can use "ulimit -n" to see the current value on your system (be sure to issue this command in the same environment that your tornado server runs as). To raise the limit you can use the ulimit command or modify /etc/security/limits.conf (try setting it to 50000).

Tornado's HTTP server does not (as of version 3.2) close connections that a web browser has left open, so idle connections may accumulate over time. This is one reason why it is recommended to use a proxy like nginx or haproxy in front of a Tornado server; these servers are more hardened against this and other potential DoS issues.

answered Jan 3 at 0:18
Ben Darnell
1,03519
 
Hi Ben, thanks for your answer, we will try to set a nginx to see how it goes. As the idle connections issue, shouldn't the timeout of 50 ms we set in our implementation handle those already? –  Will Jan 3 at 1:53
 
No, idle connections are kept alive without blocking the IOLoop (that is after all kind of the point), so the blocking threshold doesn't apply here. –  Ben Darnell Jan 3 at 2:21
 
I see. Is there some way of closing those idle connections using just Tornado itself? Using nginx as the solution is fine, we were just wondering if we could solve this issue via Tornado. –  Will Jan 3 at 2:49
 
You can turn off connection reuse completely by passing no_keep_alive=True to the HTTPServer constructor (or Application.listen) –  Ben Darnell Jan 3 at 3:41
 
Hi Ben, we just did a test by setting no_keep_alive = True in server = HTTPServer(application, no_keep_alive = True) without the nginx for now and this time our system was up for about one hour and a half (we have two virtual machines, each with its own Tornado service and a load balancer managing the requests) but after that period the time consumed started increasing and we had to turn it off. Is there some other setup in Tornado we are missing? Is there some timeout we can setup so that we avoid some sort of dead connecting taking all of Tornado's resources? –  Will Jan 3 at 16:44
show 3 more comments
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Flask, Tornado, GEvent, 以及它们的结合的性能比较
Python 从业十年是种什么体验?老程序员的一篇万字经验分享
纯python实现的web: tornado性能测试
新浪云Python Web App开发入门指南
Python打造一个在线G代码生成器
Python获取Websocket接口的数据
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服