我有一个简单的python网络服务器,它在2天/3天后一直失败。经过调查,这是因为它达到了其打开的文件数限制。打开的文件描述符是套接字。 (ls -l /proc/pid/fd/xxx:/proc/pid/fd/xxx -> socket:[yyyyy])

我可以增加ulimit,但是我想弄清楚发生了什么。

一些上下文

  • 我有50台机器,每个小时通过简单的POST id = machine_id,cpu_usage = xxx
  • 向服务器报告它们已启动并正在运行
  • 服务器仅将其存储在数据库中(mongodb)
  • 有一个用于监视事物的html页面,通过jQueryt/get json可以通过
  • 绘制给定计算机的cpu使用情况图表
  • 有一个处理程序,用于在GET?date_start,date_end,machine_id上​​给出[(date,cpu_usage)]

  • 我是唯一使用此页面的人,正如我所说的,每小时随机分发到服务器的请求只有50个

    问题可能源于:
  • jQuery的getjson打开了一个套接字,并且从不关闭它(可能是,但我不认为是这样,因为我重新启动了服务器并且没有进入监视页面)
  • python代码以及我在“main”中定义处理程序的方式
  • mongodb
  • 我无法想到的其他地方

  • main的代码:
    import listener_handler
    from flask import Flask
    
    if __name__ == '__main__':
      app = Flask(__name__)
    
      listener_handl = None
      @app.route('/listener', methods=['POST'])
      def listener():
        global listener_handl
        if listener_handl is None:
          listener_handl = listener_handler.ListenerHandler()
        return listener_handl.Post()
    
      ... (other handlers for the getjson and the static monitoring page)
    
      app.run()
    

    处理程序的代码:
    from flask import request
    
    class ListenerHandler:
      def Post(self):
        Save(request.form.get('machine_id'), request.form.get('cpu_usage'))
        return 'ok'
    

    mongo db的代码:
    import pymongo
    
    mongo_client = pymongo.MongoClient()
    mongo_db = mongo_client.stations_monitoring
    
    def Save(machine_id, cpu_usage):
      mongo_db.db['monitoring'].save({'machine': machine_id, 'cpu': cpu_usage})
    

    我试图使代码保持轻量级,我对python有很好的经验,但是对python webserver几乎没有经验,所以我真的不知道在定义处理程序时,如果每次都创建一个新的套接字,它到底是怎么回事。最后关闭,...

    我首先有一个 flask 服务器(代码在这里),然后移到 Tornado (用一些 Tornado 进口和一些app.run代替了IOLoop.instance().start()),但这导致了同样的问题

    最佳答案

    我在flask和pymongo之间遇到了完全相同的问题;我通过清理每个请求解决了它。如果您出于性能方面的考虑而将MongoClient句柄保持打开状态,则可以将其关闭。

    http://api.mongodb.org/python/current/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient.disconnect

    import pymongo
    class MongoConnector:
        def __init__(self):
            client = pymongo.MongoClient()
            self.db = client.stations_monitoring
        def close(self):
            self.db.disconnect()
    
    def Save(machine_id, cpu_usage):
        mongoConnector = MongoConnector()
        mongoConnector.db['monitoring'].save({'machine': machine_id, 'cpu': cpu_usage})
        mongoConnector.close()
    

    Flask是单线程的,您的WSGI处理程序将生成所需数量的单个应用程序,因此您无需担心Flask级别上的线程支持。

    如果您确实要保留mongo连接并出于性能的考虑而这样做,则MongoClient支持带有重新连接的A​​utoReconnect异常,因此您不必自己处理它。
    import pymongo
    from pymongo.errors import AutoReconnect
    
    class MongoConnector:
        def __init__(self):
            client = pymongo.MongoClient()
            self.db = client.stations_monitoring
        def close(self):
            self.db.disconnect()
    
    mongoConnector = MongoConnector()
    def Save(machine_id, cpu_usage):
        try:
            mongoConnector.db['monitoring'].save({'machine': machine_id, 'cpu': cpu_usage})
        except AutoReconnect:
            #should be reconnected now
            mongoConnector.db['monitoring'].save({'machine': machine_id, 'cpu': cpu_usage})
    

    [编辑]不知道你为什么不工作。尝试简化您的工作。如果您没有使用 setter/getter 的理由,那就简单一点。

    testflask.py
    from flask import Flask, request
    import pymongo
    
    app = Flask(__name__)
    
    def SaveLog(machine_id, cpu_usage):
        mc = pymongo.MongoClient()
        db = mc.stations_monitoring
        db['monitoring'].save({'machine': machine_id, 'cpu': cpu_usage})
        mc.disconnect()
    
    @app.route('/listener', methods=['POST', 'GET'])
    def listener():
        SaveLog(request.form.get('machine_id'), request.form.get('cpu_usage'))
        return 'ok'
    
    if __name__ == '__main__':
      app.run()
    

    test_get.py向服务器发送请求。矿井可以达到〜50/s
    import requests
    from random import randint
    
    while True:
        r = requests.get('http://localhost:5000/listener?machine_id=%s&cpu_usage=%s' %(randint(1,10000), randint(1,100)))
        print r.text
    

    验证fds(我的文件卡在5-10个打开的文件句柄周围)
    ps aux | grep testflask.py | grep -v grep | awk '{print $2}' | xargs -I @ bash -c 'ls -l /proc/@/fd/ | wc -l'
    

    关于python - python Web服务器上打开的套接字数量不断增加,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20540129/

    10-12 07:39
    查看更多