背景
前段时间排查了个内存泄露的故障,花了几天时间把Gunicorn + Django 从头到尾看了下。在排查问题时,网上普遍都是零碎的分析文章,需要自己多处拼接与查证,才可以勉强窥见全貌。于是萌生了写一篇按照实际流程来梳理的博客,为这次排查画上句号。
由于涉及的东西较多,如Gunicorn、wsgi、Django、元类等都可单独成文,所以将以系列文章的方式来做记录。
框架&依赖版本如下。
Django 2.1.15
Gunicorn 20.0.4
Python3.x
从启动命令开始
大部分文章都是直接看代码,但我觉得不太易懂。从启动命令开始解析我觉得会更有条理一些。
根据官方文档所示,我们的启动命令如下:
我们先从gunicorn这个入口开始。
gunicorn可执行命令从何而来
gunicorn这个命令是怎么来的呢?他到底是何方神圣?
从上图我们可以看出,gunicorn这个命令,是一个去掉了后缀的py脚本。
从这里可以引申出另外一个知识点(构建python包,有兴趣可以自行了解,具体不展开说):gunicorn的setup.py
这个gunicorn可执行文件就是从这行配置生成的。
顺着代码看下去:
class WSGIApplication(Application):
.......
# 根据配置中的路径import django(app),也就是我们的业务代码
def load_wsgiapp(self):
return util.import_app(self.app_uri)
def load_pasteapp(self):
from .pasterapp import get_wsgi_app
return get_wsgi_app(self.app_uri, defaults=self.cfg.paste_global_conf)
# 加载wsgi(也就是加载django框架生成的wsgi对象)
def load(self):
if self.cfg.paste is not None:
return self.load_pasteapp()
else:
return self.load_wsgiapp()
def run():
"""\
The ``gunicorn`` command line runner for launching Gunicorn with
generic WSGI applications.
"""
from gunicorn.app.wsgiapp import WSGIApplication
WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
查找Application,跳到 app/base.py:
class Application(BaseApplication):
.......
def run(self):
........
if self.cfg.daemon:
util.daemonize(self.cfg.enable_stdio_inheritance)
.....
super().run()
class BaseApplication<