python web服务器上打开的套接字数量不断增加

python web服务器上打开的套接字数量不断增加,python,mongodb,sockets,flask,tornado,Python,Mongodb,Sockets,Flask,Tornado,我有一个简单的PythonWebServer,它在2天/3天之后一直失败。经过调查,这是因为它达到了其打开的文件数量限制。打开的文件描述符是套接字。(ls-l/proc/pid/fd/xxx:/proc/pid/fd/xxx->socket:[yyyyy]) 我可以增加ulimit,但我更愿意弄清楚到底发生了什么 某些上下文 我有50台机器,通过一个简单的POST id=machine\u id,cpu\u usage=xxx,每小时向服务器报告它们正在启动和运行 服务器只是将其存储在数据库(

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

我可以增加ulimit,但我更愿意弄清楚到底发生了什么

某些上下文

  • 我有50台机器,通过一个简单的POST id=machine\u id,cpu\u usage=xxx,每小时向服务器报告它们正在启动和运行
  • 服务器只是将其存储在数据库(mongodb)中
  • 有一个html页面来监视事情,使用一些jquery/get json来制作一个给定机器在不同时间的cpu使用情况图表
  • 有一个处理程序用于在GET?date\u start、date\u end、machine\u id上提供[(日期、cpu使用情况)]
我是唯一一个使用此页面的人,正如我所说的,每小时只有50个请求随机分发到服务器

问题可能源于:

  • jquery的
    getjson
    打开了一个套接字,但从未关闭它(可能是,但我不这么认为,因为我重新启动了服务器,没有进入监控页面)
  • python代码和我在“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方面有很好的经验,但在PythonWebServer方面几乎没有经验,所以当我定义处理程序时,我真的不知道到底发生了什么,如果每次都创建一个新套接字,如果它在最后关闭


我首先有一个flask服务器(代码在这里),然后转移到tornado(由几个tornado导入和一些IOLoop.instance().start())代替
app.run
),但这导致了相同的问题

我在flask和Pymango之间有完全相同的问题;我通过清理每个请求来解决它。如果您没有性能原因而不打开MongoClient句柄,那么最好将其关闭

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

如果您确实想要持久化mongo连接,并且出于性能原因,MongoClient支持带有重新连接的AutoReconnect异常,因此您不必自己处理它

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})
[编辑]不知道为什么你的不起作用。试着简化你正在做的事情。如果你没有获得成功的理由,那就简单一点

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个打开的文件句柄)


我们使用的是pymongo+flask+gunicorn,一切正常。pymongo将维护一个连接池,每个MongoClient实例都有一个内置的连接池。因此,如果运行的mongoclient实例太多,它可能会抱怨打开的文件太多


非常感谢。为了确定,您希望在
try/except AutoReconnect
之后调用close(),对吗?但如果这样做,它如何保持连接以提高性能?如果没有,它如何解决关闭插座的问题?我不确定文档说了什么不,第二个示例显示了我如何持久化MongoClient对象,mongoConnector需要在flask进程期间(永远)打开,并且您让MongoClient类为您重新连接。在我的情况下,我使用了第一个简单地打开和关闭MongoClient句柄的示例,因为我没有性能问题要求我保持连接。我明白你的意思,你只看到启动时打印新连接一次?我不理解你的第二个示例和我的第二个示例之间的区别,因为您没有显式调用
close()
。我的代码中也没有出现任何异常(尽管我明白自动重新连接的意义)对不起,我不认为有什么区别。撇开重新连接不谈,我只是不明白为什么你需要一个getter函数,而你可以直接声明它。谢谢你的链接。他们建议只打开一个客户机,但这是我首先做的(检查mongo_客户机是否没有),我有错误。我用文档中给出的max_pool_size等参数重新开始,并将看到……您能否分享如何使用pymongo、打开客户端、执行查找或保存……的代码?我已经被这个问题困扰了两个星期,但仍然无法解决这个问题,这是一个愚蠢的问题,但那些pymongo与mongod进程的联系是否仍然存在?不是你过程中的另一部分吗?你是对的,我不久前解决了部分问题。套接字与mongodb无关。它位于远程计算机(客户端)和服务器之间。客户端建立了连接,但是它的internet连接很糟糕,所以它永远挂起。在curl上添加超时有帮助。但我不知道为什么烧瓶或龙卷风不处理这个?
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
ps aux | grep testflask.py | grep -v grep | awk '{print $2}' | xargs -I @ bash -c 'ls -l /proc/@/fd/ | wc -l'