Gunicron-gevent-Mongodb数据库连接一直增加不释放

38次阅读

共计 1335 个字符,预计需要花费 4 分钟才能阅读完成。

问题描述

  • 使用 Flask 开发的 Web 服务,部署在服务器上使用的是 gunicorn manage:app -k gevent -w 4
  • 某日告警,说浏览器崩了,当时急急忙忙的重启,搞好了,因为所有的服务都正常运行,后面查看日志,也没有发现什么特别的地方,最终感觉因该是 MongoDB 连接数满了,本地测试发现确实是连接数一直增加,不会释放。

解决过程

关于 Gunicron

  • 什么是 Gunicron:是一个 unix 上被广泛使用的高性能的 Python WSGI UNIX HTTP Server。和大多数的 web 框架兼容,并具有实现简单,轻量级,高性能等特点。

    • 深入理解 uwsgi 和 gunicorn 网络模型
  • 为什么要使用 Gunicron:用于接受 http 请求并转换为 WSGI 协议,以供实现了 WSGI 协议的 flask 使用,并且 gunicorn 得益于 gevent 等技术,大幅度提高了性能,在生产环境以替代框架自带的 WSGI server。

生产环境

  • 配置

    gevent==1.3.6
    greenlet==0.4.14
    gunicorn==19.9.0
    pymongo==3.7.0

  • mongodb 连接代码
    def __init__(self):
        config_name = os.getenv('FLASK_CONFIG') or 'default'
        base_config = config[config_name]  # object
        self.client = MongoClient(host=base_config.MONGO_HOST, port=base_config.MONGO_PORT)
        db_name = base_config.MONGO_NAME
        self.db = self.client[db_name]

修改方案

  • 参考 pymongo: MongoClient opened before fork 错误排解
  • fork 是启动新进程的方法,由于 MongoClient 不是进程安全的,所以不可以将该实例从父进程中复制到子进程当中。在这个 flask 应用中,flask 使用 gunicorn 作为网关接口,在启动的时候会启动一个主进程和多个子进程,也就是 master/workers,这个时候就出现了 MongoClient 实例在进程之间的传递。
  • 为了解决这个问题,在实例化 MongoClient 对象的时候要加上 connect=False 参数。
    def __init__(self):
        config_name = os.getenv('FLASK_CONFIG') or 'default'
        base_config = config[config_name]  # object
        self.client = MongoClient(host=base_config.MONGO_HOST, port=base_config.MONGO_PORT, maxIdleTimeMS=300000, connect=False)
        db_name = base_config.MONGO_NAME
        self.db = self.client[db_name]

参考

  • 用 gevent 来 host wsgi server,mysql 能否长连接
  • python – Mongo 连接从未发布 – Django 和 Mongoengine 在 gevent 上使用 gunicorn

正文完
 0