Laravel 队列 - 如何设置 FAST 处理器

Laravel Queue - How to setup a FAST processor

我正在使用 Laravel 5.5 并且正在尝试设置一些快速队列处理。我 运行 遇到了一个又一个障碍。

此站点是一项employer/employee匹配服务。因此,当雇主 post 提供工作职位时,它需要 运行 通过我们系统中的所有员工并计算一些变量以确定他们与工作的匹配程度。我们已经弄清楚了这一切,但是当系统中有数千名员工时,一次处理一个需要很长时间。所以,我准备写几个 table。第一个是定义位置 ID 和状态的简单 table。第二个是 table 列出所有员工 ID、职位 ID 和正在处理的员工的状态。这只需要几秒钟的时间来编写,然后允许用户在应用程序中继续。

然后我有另一个服务器设置为 运行 每分钟检查第一个 table 中的新条目的 cron。找到后,它将其标记为已启动,然后通过每个员工获取所有员工和 运行s,并在 Laravel 中开始排队作业。我定义的作业确实正确地提交到队列并且 运行ning queue:work 实际上确实正确地处理了该作业。这都是经过测试的。

但是,我 运行 遇到的问题是我尝试了数据库 (MySQL)、Redis 和 SQS 作为队列,它们都非常慢。我正在使用同一台服务器尝试操作 queue:work(使用 Supervisor 并尝试 运行 多达 300 个进程)但随后创建了 3 个克隆,它们不 运行 cron 但仅运行 Supervisor(每个克隆 100 个进程)并在第一台服务器上杀死了 Supervisor。使用数据库它会处理正常,尽管 运行 到 10k 排队作业需要几个小时,但是使用 SQS 和 Redis 我遇到了很多失败。脚本花费的时间太长或其他原因。我检查了克隆 运行 工人的 CPU,他们几乎没有达到 40%,所以我没有对服务器过度征税。

我刚刚阅读了有关 Horizo​​n 的内容,但我不确定它是否会对这种情况有所帮助。我一直在尝试查找有关如何使用 Laravel 正确设置队列处理系统的信息,只是 运行 问题多于答案。

有没有人熟悉这些东西并且对如何正确设置它有任何建议,以便它非常快速且无故障(假设我的代码没有错误)?

更新:根据其他一些 post 建议,我想我会分享更多细节:

  1. 我使用 Forge 作为 AWS EC2 服务器和 2G RAM 的设置工具。
  2. 三个克隆中的每一个都具有以下工作器配置:

    command=php /home/forge/default/artisan queue:work sqs --sleep=10 --daemon --quiet --timeout=30 --tries=3  
    
    process_name=%(program_name)s_%(process_num)02d  
    autostart=true  
    autorestart=true  
    stopasgroup=true  
    killasgroup=true  
    user=forge  
    numprocs=100  
    stdout_logfile=/home/forge/.forge/worker-149257.log
    
  3. 数据库在 Amazon RDS 上。

我很好奇 Laravel 缓存是否可以与队列系统一起使用。每个 运行 都有一些排队脚本的元素,所以也许如果我从一开始就将数据排队,可能会节省一些时间。但我不相信这会是一个巨大的进步。

如果忽略每个作业实际处理的逻辑,只考虑运行个作业的开销,Laravel的排队系统可以轻松在问题中描述的环境中每小时处理 10,000 个作业,如果不是数倍的话——尤其是使用 Redis 后端时。

对于典型的队列设置,每个框 100 个队列工作进程似乎非常高。除非这些作业花费大量时间处于 waiting 状态——例如通过网络向 Web 服务发出请求并且只用几毫秒来处理响应的作业——大量的并发处理 运行 实际上会降低性能。每个处理器核心的 运行 多于一名工作人员,我们不会获得太多收益。额外的工作人员会产生开销,因为操作系统必须在所有竞争进程之间划分和安排计算时间。

I checked the CPUs on the clones running the workers and they are barely hitting 40% so I'm not over-taxing the servers.

在不了解该项目的情况下,我可以建议这些工作可能会花费 一些 的时间来等待某事。您可能需要调整工作人员的数量,以找到空闲时间和过度拥挤之间的最佳平衡点。

With database it would process ok, though to run through 10k queued jobs would take hours, but with sqs and redis I'm getting a ton of failures.

如果您将错误消息和任何其他相关信息添加到问题中,我将尝试更新此答案。

I'm curious if the Laravel cache will work with the queue system. There's elements of the queued script that are common to every run so perhaps if I queued that data up from the beginning it may save some time.

我们当然可以在队列中执行作业时使用缓存API。我们看到的任何性能改进都取决于为我们可以存储在缓存中的每个作业再现数据的成本。我不能肯定地说 缓存会节省多少时间,因为我不熟悉该项目,但您可以分析作业中的代码部分以找到昂贵的操作。

或者,我们可以在内存中缓存可重用数据。当我们使用 artisan queue:work 初始化队列工作程序时,Laravel 启动一个 PHP 进程并启动应用程序 once for all 工作人员执行的作业。这与典型 PHP 网络应用程序的应用程序生命周期不同,其中应用程序会针对 每个请求 重新启动并在每个请求结束时处理状态。因为每个作业都在同一个进程中执行,我们可以创建一个对象在进程内存中缓存共享作业数据,也许通过将单例绑定到 IoC 容器中,作业读取速度甚至比 Redis 缓存存储快得多,因为我们避免了从缓存后端获取数据所需的开销。

当然,这也意味着我们需要确保我们的作业不会泄漏内存,即使我们没有如上所述缓存数据。

I was just reading about Horizon and I'm not sure if it would help the situation.

Horizo​​n 提供了一项监控服务,可能有助于追踪此设置的问题。如果应用程序使用 Horizo​​n 可以在空闲时分配工作的其他队列,它也可能会提高一点效率,但问题似乎并不表明是这种情况。

Each of the three clones has the following worker configuration:

command=php /home/forge/default/artisan queue:work sqs --sleep=10 --daemon --quiet --timeout=30 --tries=3

(旁注:对于 Laravel 5.3 及更高版本,不推荐使用 --daemon 选项,并且 queue:work 命令默认以守护进程模式运行。)