更新突增大量服务进程


简单记录一下问题的排除过程,和对应的处理方式!

更新突增大量服务进程


周末监控告警,发现有一个容器服务,占用了大量的内存(几十个GB的内存)资源,导致服务节点有些卡顿,影响其他服务的使用。随即,登录服务器查看,发现有大量的 gunicorn 进程(一百多个)。依据该服务的历史数据分析,正常情况下,应该在 4-6 个之间才比较合理。找开发确认之后,发现并没有开启大量并发任务。

root@6123d6c9a23e:/app# ps -ef | grep gunicorn
app  /usr/bin/python3 /usr/local/bin/gunicorn -c python:app.worker.gunicorn_conf
app  /usr/bin/python3 /usr/local/bin/gunicorn -c python:app.worker.gunicorn_conf
app  /usr/bin/python3 /usr/local/bin/gunicorn -c python:app.worker.gunicorn_conf
app  /usr/bin/python3 /usr/local/bin/gunicorn -c python:app.worker.gunicorn_conf
......

看了下服务日志,发现大量如下所示的信息,比较奇怪。确认该服务并不会影响客户使用,手动删除部分进程(1/5),发现并没有新增,后续将其恢复到合理范围之内。

# 服务log日志信息
I[autoreload.py:199]: /app/data/xxx.py modified; restarting server
I[autoreload.py:199]: /app/plugins/xxx.py modified; restarting server
......

确认之前该服务都可以正常运行,怀疑是开发提交代码导致该问题的出现,随即看了下最近提交的代码。看了比较久的时候,才发现 tornado 框架有一个 autoreload 的特性,与服务启动时,所使用的 gunicornsupervisor 工具有冲突,都是重载服务。

正常情况下,调试使用的 debug 功能,只能在开发本地测试的时候使用才对,线上环境是不应该开启的(误提交了)。且如果开启了 debug 功能,会默认开启 autoreload 特性,这就导致服务不断重载和重启,导致占用了大量内存资源。

class Application(tornado.web.Application):
    def __init__(self):
        handlers = route.init_handlers()
        settings = {}
        tornado.web.Application.__init__(self, handlers, debug=config.get_config("debug", True), **settings)
  • [1] 直接关闭 autoreload 特性
class Application(tornado.web.Application):
    def __init__(self):
        handlers = route.init_handlers()
        settings = {'autoreload': False}
        tornado.web.Application.__init__(self, handlers, debug=config.get_config("debug", True), **settings)
  • [2] 直接关闭 debug 功能 - 包含 autoreload 特性 - 推荐直接关闭
class Application(tornado.web.Application):
    def __init__(self):
        handlers = route.init_handlers()
        settings = {}
        tornado.web.Application.__init__(self, handlers, debug=config.get_config("debug", False), **settings)

到这里,可能你已经知道了,为什么日志里面会出现大量的 restart 信息了。是因为,同步服务代码时变更新了代码文档,然后 tornado 配置了 autoreload 特性,导致服务重载。然后 supervisor 发现服务挂了,再来一次。

变更了多少文档,就导致重载了几次,然后会被重复拉几次,最后 CI 推送完成发送 HUP 信号给 gunicornreload 一次,这就出现了上文中所说的,一百多个进程 的出现。

# 服务log日志信息
I[autoreload.py:199]: /app/data/xxx.py modified; restarting server
I[autoreload.py:199]: /app/plugins/xxx.py modified; restarting server
......

文章作者: Escape
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Escape !