我有一个简单的python网络服务器,它在2天/ 3天后仍然失败。经过调查,这是因为它达到了打开限制的文件数量。打开的文件描述符是套接字。 (ls -l /proc/pid/fd/xxx
:/proc/pid/fd/xxx -> socket:[yyyyy]
)
我可以增加ulimit,但我想知道发生了什么。
某些背景
我是唯一使用此页面的人,正如我所说,每小时只有50个请求随机分发到服务器
问题可能源于:
getjson
打开了一个套接字并且从不关闭它(可能是但我不这么认为,因为我重新启动了服务器而没有进入监控页面)主要代码:
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,所以当我定义处理程序时,如果每次都创建一个新套接字,我真的不知道引擎盖下发生了什么,如果它在结束时关闭,......
我首先有一个烧瓶服务器(这里是代码),然后转移到龙卷风(由一些龙卷风进口和一些app.run
替换IOLoop.instance().start()
)但这导致了同样的问题
答案 0 :(得分:1)
我在烧瓶和pymongo之间有完全相同的问题;我通过清理每个请求解决了这个问题。如果您没有性能原因让MongoClient句柄保持打开状态,您也可以关闭它。
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处理程序将生成所需数量的单个应用程序,因此您无需担心烧瓶级别的线程支持。
如果你真的想坚持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个打开文件句柄挂起)
ps aux | grep testflask.py | grep -v grep | awk '{print $2}' | xargs -I @ bash -c 'ls -l /proc/@/fd/ | wc -l'
答案 1 :(得分:0)
我们正在使用pymongo + flask + gunicorn,一切都很好。 pymongo将维护一个连接池,每个MongoClient实例都有一个内置的连接池。因此,如果您运行的mongoclient实例太多,可能会抱怨打开的文件太多。