Heroku 上的 Gunicorn Flask 服务器在重新启动 Worker 之前终止了最后一个请求,导致出现 503 错误:“连接关闭而没有响应。”
我已经分析了数百个这样的请求,每当服务器遇到“连接关闭而没有响应”时, “错误,它总是发生在特定工作程序重新启动之前的最后一次调用上。
我在 Gunicorn 服务器上设置了以下设置:
web: gunicorn main:app --threads=3 --max-requests=1200
每个 dyno 中有 4 个工作程序。
gunicorn==22.0.0|| |值得注意的是,最后一次出错的调用始终是零服务时间。
我已更新到最新的gunicorn版本,但没有效果 也尝试增加和减少线程+工作人员 数据库的延迟也减少了
I have updated to latest gunicorn version but it had not effect tried increasing and decreasing the threads + workers as well reduced latency of database too
你的问题很可能与 Gunicorn 的
--max-requests
设置和 Heroku 的路由机制有关。
问题根源:
-
--max-requests
: 你设置了--max-requests=1200
,这意味着每个 Gunicorn 工作进程在处理 1200 个请求后会自动重启。这是为了防止内存泄漏等问题。 - Heroku 路由器和连接保持: Heroku 的路由器可能会将请求随机分配给任何可用的 Gunicorn 工作进程,即使该进程即将重启。如果一个请求被路由到一个即将关闭的进程,该请求可能会在没有得到任何响应的情况下被终止,从而导致“连接关闭而没有响应”错误。
解决方法:
你有几个选择可以解决这个问题:
1. 使用
pre_request
钩子优雅地关闭工作进程:
-
在你的 Flask 应用中,你可以使用 Gunicorn 的
pre_request
钩子来检查当前工作进程是否已接近max_requests
限制。 -
如果接近限制,你可以使用
werkzeug.exceptions.ServiceUnavailable
异常来拒绝新请求,并返回 503 服务不可用错误。这将允许当前工作进程完成处理中的请求,然后优雅地关闭。
```python from flask import Flask, g from werkzeug.exceptions import ServiceUnavailable
app = Flask( name )
@app.before_request def check_max_requests(): if g.worker.requests_count >= g.worker.max_requests - 10: raise ServiceUnavailable('Server is restarting soon')
@app.teardown_appcontext def close_db(error): db = getattr(g, '_database', None) if db is not None: db.close() ```
2. 增加
--max-requests
的值:
-
你可以尝试增加
--max-requests
的值,例如将其设置为--max-requests=2400
或更高。 - 这可能会减少工作进程重启的频率,但并不能完全解决问题。
3. 禁用
--max-requests
:
-
你可以完全删除
--max-requests
选项,但这意味着 Gunicorn 工作进程将不会自动重启。 - 你需要确保你的应用程序没有内存泄漏或其他可能导致问题的问题。
4. 使用其他 WSGI 服务器:
- 你可以考虑使用其他 WSGI 服务器,例如 uWSGI 或 Waitress,它们可能具有不同的工作进程管理机制。
建议:
我建议你首先尝试方法 1,因为它提供了最优雅和最可靠的解决方案。 如果你发现方法 1 对你的应用程序来说太复杂,你可以尝试方法 2 或 3,但请注意它们的潜在缺点。
其他建议:
- 确保你的数据库连接池配置正确,并且连接在使用后被正确释放。
- 监控你的应用程序的内存使用情况,以确保没有内存泄漏。
希望这些信息能帮到你!
标签:python,flask,heroku,gunicorn From: 78782064