Celery:为什么 gevent 和 eventlet 比 prefork 池更慢且更不可靠?

Nei*_*eil 6 python celery gevent eventlet

我的主 celery 应用程序在 AWS 的 EC2 实例(“main”)中运行,它生成的任务与同一可用区(“db”)中的 RDS 数据库进行交互。工作负载每分钟生成多达数千个任务,我需要尽快并行执行它们。我有工作人员在两个物理位置执行任务。一个来自主实例的单独 EC2 实例(“工作 EC2”),但与它和数据库位于同一可用区,另一个来自我们办公室私有数据中心的物理计算机(“工作本地”)。

工作 EC2 和本地都运行 prefork 事件池并且autoscale==70,4工作正常(任务在 2-3 秒内完成),但 CPU 和内存使用率很高,如果可能的话,我需要更多的并行性。所以我一直在尝试eventlet和。我陷入以下问题:geventconcurrency=100

  • Worker EC2 上的 Eventlet 任务完成时间 (1s) 比 prefork (2-3s) 快。然而,在本地工作线程上,任务完成时间要慢得多(17-25 秒),并且大多数时间都卡在使用本地 Redis 缓存对数据库和 I/O 执行简单查询上。该进程不会对 CPU 和内存造成很大的负担。Gevent 本地工人也会出现同样的问题,但更严重。任务在 200 秒以上完成。
  • Worker EC2 上的 Eventlet 任务完成时间更快,但它似乎没有使用完全并发。尽管每个任务都在 1-1.5 秒内完成,但我从未见过在任何给定的一秒窗口内完成超过 10-15 个任务。所以看起来完全并发没有被利用。CPU 利用率为 60-80%,内存利用率低于 50%,因此不会承受重压。
  • 即使任务在队列中,运行 Gevent 和 Eventlet 的本地工作线程也经常处于空闲状态。一旦我重新启动工作程序,它就会再次开始消耗任务一段时间,然后再次空闲。我注意到在这些情况下工作人员会出错BrokenPipe。注意,这种情况不会发生在 prefork 上,所以我认为这不是连接/网络的问题,而是与池包有关。这种行为对于 Gevent 来说比 Eventlet 更糟糕,但两者都不好

问题:

  • 为什么 Eventlet 和 Gevent 在本地和 EC2 工作线程之间的表现会不同?这两个工作人员之间的唯一区别在于,其中一个工作人员在物理上更接近主芹菜应用程序和数据库,这会影响绿色线程的执行方式吗?

  • 如何让Eventlet真正利用完整的并发设置?

  • 为什么 Gevent 需要这么长时间才能访问内存缓存?

  • 如何让远程工作人员上的 Eventlet/Gevent 持续消耗任务?

    注意:使用 prefork 的相同工作人员在完全相同的设置下不会出现这些问题。prefork 的唯一问题是,即使并发数为 70,工作机器的 CPU 和内存也会承受很大的负担,我希望它接近 700。