【问题标题】:Django bulk_upsert saves queries to memory causing memory errorsDjango bulk_upsert 将查询保存到内存中导致内存错误
【发布时间】:2019-09-07 17:04:45
【问题描述】:

对于我们的 Django Web 服务器,我们的资源非常有限,这意味着我们必须小心使用的内存量。我们的 Web 服务器的一部分是一个 crom 作业(使用 celery 和 rabbitmq),它将一个约 130MB 的 csv 文件解析到我们的 postgres 数据库中。 csv 文件保存到磁盘,然后使用 python 中的 csv 模块读取,逐行读取。因为 csv 文件基本上是一个提要,所以我们使用来自 django-postgres-extra 的自定义 postgres 管理器中的 bulk_upsert 来更新我们的数据并覆盖现有条目。最近我们开始遇到内存错误,我们最终发现它们是由 Django 引起的。

运行 mem_top() 向我们展示了 Django 在内存中存储了大量的 upsert 查询(INSERT ... ON CONFLICT DO),包括它们的元数据。 15000 行中的每个bulk_upsert 都会增加 python 使用的 40MB 内存,当我们总共插入 750.000 行时,作业完成时总共使用 1GB 内存。显然 Django 在完成后不会从内存中释放查询。在没有 upsert 调用的情况下运行 crom 作业将导致最大内存使用量为 80MB,其中 60MB 是 celery 的默认值。

我们尝试运行gc.collect()django.db.reset_queries(),但查询仍存储在内存中。我们的Debug 设置为false,CONN_MAX_AGE 也没有设置。目前我们没有找到解决这个问题的线索,我们现在无法运行我们的 crom 作业。您知道尝试解决此问题的任何最后手段吗?

更多关于我们服务器的元信息:

django==2.1.3
django-elasticsearch-dsl==0.5.1
elasticsearch-dsl==6.1.0
psycopg2-binary==2.7.5
gunicorn==19.9.0
celery==4.3.0
django-celery-beat==1.5.0
django-postgres-extra==1.22

非常感谢您!

【问题讨论】:

  • 您是否尝试过将 csv 数据分批而不是一次全部传递给bulk_insert
  • 我正在批量传递 CSV 数据。如前所述,我在更新数据之前将它们分组为 15000 个。问题是这些批处理查询被保存在内存中并且永远不会被释放。由于每个查询大约 40MB,这会导致内存错误,因为我们总共插入了 750.000 行,这相当于最终使用了大约 1000MB 的内存。

标签: django postgresql memory-leaks out-of-memory upsert


【解决方案1】:

今天我找到了解决我们问题的方法,所以我觉得很高兴分享。事实证明,问题是 Django 和 Sentry(我们只在生产服务器上使用)的组合。 Django 会记录查询,然后 Sentry 会捕获此日志并出于某种原因将其保存在内存中。由于每个原始 SQL 查询大约 40MB,这会占用大量内存。目前,我们在 crom 作业服务器上关闭了 Sentry,并正在寻找一种方法来清除 sentry 保存的日志。

【讨论】:

    猜你喜欢
    • 2015-05-18
    • 1970-01-01
    • 2019-08-26
    • 2017-03-14
    • 1970-01-01
    • 2014-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多