我有一个非常简单的查询,在一个非常简单的表:
def get_defaults(domain):
defaults = BaseDefaults.query.filter_by(domain=domain).first()
return defaults
表有(不开玩笑)3行,34列,1 PK, 1 Unique, 2 FK。以下类型的:
Timestamp: 2 Cols
Integer: 5 Cols
Booleans: 8 Cols
VarChar(100) & Varchar(250): 19 Cols
通常,这些列中大约有5-8列为空值。这个函数运行在一个芹菜任务的上下文中,该任务内存爆满(1.2Gb),而另一个正在运行的任务使用了大约110Mb的内存。
所以我用memory_profiler
来分析代码,结果这个特定的函数defaults = get_defaults(domain)
消耗了大约800-900Mb的RAM,这完全没有意义。
我在本地没有看到同样的行为——它只发生在Kubernetes集群(托管在DigitalOcean上),所以很难理解可能发生了什么。
函数查询一个托管在RDS上的Postgres DB,它似乎工作得很好(从本地pc查询,或从SQL客户端工作不到200ms)。
我还发现,大部分高内存消耗发生在第一次运行查询时,在第二次运行查询时(另一个任务运行),同一行增加了大约120Mb的使用,这似乎更合理。所以可能的情况是,在Flask-SQLAlchemy中的会话管理也在芹菜中得到的方式。
它正在消耗集群内的大量RAM,并威胁到节点的健康。如果我将pod消耗限制为512Mb,那么pod会被创建,但之后就会死亡。
对于如何排除故障,优化,解决这个问题有什么想法吗?
对于任何正在经历类似事情的人,我在backref
模型声明中修复了lazy=True
的问题。
这不是一个问题,直到数据库中一个完全不同的表开始快速增长——我们使用lazy='joined'
,它会自动连接所有用BsaeDefaults
声明关系的表。
通过使用lazy=True
,您只加载您查询的表,因此pod中的内存消耗从1.2Gb下降到140Mb。