Flask默认开发服务器连接PostgreSQL出现too many open files错误求助
解决"too many open files"错误的方案
核心问题分析
- 未实际利用pgbouncer连接池:你的
get_db_connection函数直接连接PostgreSQL数据库,而非pgbouncer的监听地址,等于绕过了连接池管理,每个请求都会新建数据库连接,高并发场景下很快耗尽系统文件句柄(每个数据库连接对应一个socket文件)。 - 异常处理存在连接泄漏风险:
except块中使用cur.execute('rollback')是错误操作,正确的回滚方式是调用conn.rollback();若此处抛出异常,后续的游标和连接关闭逻辑可能无法执行,导致连接资源泄漏。 - Flask默认服务器不适合高并发:Flask自带的开发服务器为多线程模式,但性能有限,面对IoT设备高频推送的请求时,易引发资源耗尽问题。
具体修复步骤
1. 修改数据库连接,接入pgbouncer
将get_db_connection中的连接目标改为pgbouncer的地址和端口,而非直接连接PostgreSQL:
def get_db_connection(): conn = psycopg2.connect( dbname="database", port="6432", # 替换为pgbouncer实际监听端口,默认6432 host="pgbouncer_host", # 替换为pgbouncer所在的IP或主机名 user="username", password="password", cursor_factory=psycopg2.extras.RealDictCursor ) return conn
2. 修复异常处理与资源释放逻辑
使用finally块确保无论请求是否成功,游标和连接都能被正确关闭,同时修正回滚操作并优化SQL执行方式:
@app.route('/aqi/add', methods=['POST']) def addAQI(): conn = None cur = None response = None try: conn = get_db_connection() cur = conn.cursor() if request.method == 'POST': data = request.form # 数据获取逻辑保持不变 co_ugm3 = data.get('co', default=0) no2_ugm3 = data.get('no2', default=0) so2_ugm3 = data.get('so2', default=0) o3_ugm3 = data.get('o3', default=0) co2_ugm3 = data.get('co2', default=0) tvoc = data.get('tvoc', default=0) pm1_ugm3 = data.get('pm1', default=0) pm25_ugm3 = data.get('pm25', default=0) pm4_ugm3 = data.get('pm4', default=0) pm10_ugm3 = data.get('pm10', default=0) noise_dba = data.get('noise', default=0) datetime = data.get('datetime') h2s_ugm3 = data.get('h2s', default=0) station_name = data.get('station') battery_voltage_dc = data.get('battery', default=0) temperature_celsius = data.get('tmp', default=0) relative_humidity_percent = data.get('hr', default=0) barometric_pressure_hpa = data.get('hpa', default=0) station_id = data.get('station_id') # 使用参数化查询避免SQL注入,同时提升执行效率 cur.execute(""" INSERT INTO nifx_devices_data( co_ugm3, no2_ugm3, so2_ugm3, o3_ugm3, co2_ugm3, tvoc, pm1_ugm3, pm25_ugm3, pm4_ugm3, pm10_ugm3, noise_dba, datetime, h2s_ugm3, station_name, battery_voltage_dc, temperature_celsius, relative_humidity_percent, barometric_pressure_hpa, station_id ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """, ( co_ugm3, no2_ugm3, so2_ugm3, o3_ugm3, co2_ugm3, tvoc, pm1_ugm3, pm25_ugm3, pm4_ugm3, pm10_ugm3, noise_dba, datetime, h2s_ugm3, station_name, battery_voltage_dc, temperature_celsius, relative_humidity_percent, barometric_pressure_hpa, station_id )) conn.commit() response = Response(response=json.dumps({'Status': 1}), mimetype='application/json') response.status_code = 200 except Exception as e: if conn: conn.rollback() print(e) response = Response(response=json.dumps({'Status': 0}), mimetype='application/json') response.status_code = 400 finally: # 强制关闭游标和连接,避免资源泄漏 if cur: cur.close() if conn: conn.close() return response
3. 调高系统文件句柄限制
若服务运行在Linux系统,可临时调高当前进程的文件句柄限制:
ulimit -n 65535
要永久生效,编辑/etc/security/limits.conf文件并添加:
* soft nofile 65535 * hard nofile 65535
同时调整pgbouncer配置文件(pgbouncer.ini)中的连接池参数:
max_client_conn = 1000 # 允许的最大客户端连接数 default_pool_size = 20 # 每个数据库的默认连接池大小
4. 替换Flask默认服务器
Flask默认开发服务器不适合生产高并发场景,改用Gunicorn或uWSGI:
# 安装Gunicorn pip install gunicorn # 启动服务,根据服务器配置调整进程和线程数 gunicorn --workers 4 --threads 2 app:app
内容的提问来源于stack exchange,提问作者Shahzad Bacha
相关产品推荐
相关产品推荐

