高 SQLAlchemy 初始化开销

High SQLAlchemy initialization overhead

我们目前正在使用 Flask RQ 以及 Flask SQLAlchemy 和 运行 解决一些性能问题。这是我们的高级架构:

  1. API 端点被命中
  2. 耗时的任务排队进入 RQ
  3. RQ worker fork 一个新进程来执行作业
  4. 作业通常包括通过 Flask 进行的数据库查询 SQLAlchemy + 附加处理

在使用 cProfile 查看 (4) 的性能时,我看到

1       5.7e-05     5.7e-05     4.064   4.064   __init__.py:496(__get__)
535/1   0.002901    0.002901    3.914   3.914 base.py:389(_inspect_mapped_class)
1       0.001281    0.001281    3.914   3.914   mapper.py:2782(configure_mappers)
462/1   0.000916    0.000916    3.914   3.914   base.py:404(class_mapper)
1       1.4e-05     1.4e-05     3.914   3.914   mapper.py:1218(_configure_all)
59      0.01247     0.0002113   3.895   0.06601 mapper.py:1750(_post_configure_properties)
985/907 0.01748     1.927e-05   3.29    0.003627    interfaces.py:176(init)
235/157 0.00914     5.822e-05   3.162   0.02014 relationships.py:1650(do_init)
...

我看到很多时间花在 SQLAlchemy 上;我假设这是将 SQL 数据映射到 ORM 对象的一些开销。所以,我有两个问题:

  1. 初始化 SQL-ORM 映射所花费的时间是否符合预期?我 运行 在 AWS xlarge 实例上的使用率为 70% CPU。根据 pg_stat_statements.
  2. ,我所有的关系都是使用 lazy='dynamic' 动态加载的,相应的查询耗时 < 10 毫秒
  3. 假设无法解决 (1),另一种避免持续开销的方法是使用 this 这样的队列。因此,不是为每个作业分叉一个新进程,作业直接在线程中运行。这对分布式系统是可取的吗?我找不到执行此操作的框架,所以这可能不是个好主意?

最后请注意,如果我是愚蠢的并且没有看到明显的解决方案,请告诉我!

configure_mappers 通常在应用程序的生命周期内只被调用一次。它设置了一些内部簿记以使您的模型可用。您应该避免 运行 它用于每个分叉进程。为此,在分叉之前在父进程中手动调用一次:

from sqlalchemy.orm import configure_mappers

configure_mappers()