And*_*sen 4 php queue laravel laravel-5.5 laravel-horizon
我正在使用 Laravel 5.5 并且我正在尝试设置一些快速队列处理。我遇到了一个又一个的障碍。
该网站是雇主/雇员匹配服务。因此,当雇主发布工作职位时,它需要遍历我们系统中的所有员工并计算一些变量,以确定他们与工作的匹配程度。我们已经弄清楚了这一切,但是当系统中有数千名员工时,一次处理一个需要很长时间。所以,我准备写几个表。第一个是定义位置 ID 和状态的简单表。第二个表列出了所有员工 ID、职位 ID 和正在处理的员工的状态。这只需几秒钟即可写入,然后允许用户在应用程序中继续前进。
然后我有另一个服务器设置,每分钟运行一个 cron,检查第一个表中的新条目。找到后,它会将其标记为已开始,然后抓取所有员工并遍历每个员工并在 Laravel 中启动排队作业。我定义的作业确实正确提交到队列,而运行queue:work
实际上确实正确处理了作业。这都是经过测试的。
但是,我遇到的问题是,我已经为队列尝试了数据库 (MySQL)、Redis 和 SQS,但它们都非常慢。我正在使用同一台服务器来尝试操作queue:work
(使用 Supervisor 并尝试运行多达 300 个进程),但随后创建了 3 个不运行 cron 而仅运行 Supervisor(每个克隆 100 个进程)的克隆,并在第一个服务器。使用数据库它可以正常处理,尽管运行 10k 排队作业需要几个小时,但是使用 SQS 和 Redis 我遇到了很多失败。脚本花费的时间太长或什么的。我检查了运行 worker 的克隆上的 CPU,它们几乎没有达到 40%,所以我不会对服务器过度征税。
我只是在阅读有关地平线的信息,我不确定它是否对这种情况有所帮助。我一直在寻找有关如何使用 Laravel 正确设置队列处理系统的信息,并且一直遇到的问题多于答案。
有没有人熟悉这些东西并且对如何正确设置它有任何建议,以便它非常快速且无故障(假设我的代码没有错误)?
更新:根据其他一些帖子建议,我想我会分享更多细节:
三个克隆中的每一个都具有以下工作器配置:
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
Run Code Online (Sandbox Code Playgroud)数据库位于 Amazon RDS 上。
我很好奇 Laravel 缓存是否适用于队列系统。排队脚本的元素对于每次运行都是通用的,所以如果我从一开始就将数据排队,可能会节省一些时间。但我不相信这会是一个巨大的进步。
如果我们忽略每个作业处理的实际逻辑,只考虑运行作业的开销,Laravel 的排队系统每小时可以轻松处理 10,000 个作业,如果不是数倍,在问题描述的环境中——尤其是在有 Redis 后端的情况下.
对于典型的队列设置,每盒 100 个队列工作进程似乎非常高。除非这些作业花费大量时间处于等待状态——例如通过网络向 Web 服务发出请求并仅使用几毫秒来处理响应的作业——否则并发运行的大量进程实际上会降低性能。每个处理器核心运行一个以上的工作程序不会让我们获得太多收益。额外的工作人员会产生开销,因为操作系统必须在所有竞争进程之间划分和安排计算时间。
我检查了运行 worker 的克隆上的 CPU,它们几乎没有达到 40%,所以我不会对服务器过度征税。
在不了解该项目的情况下,我可以建议这些工作确实可能会花费一些时间等待某事。您可能需要调整工作人员的数量以找到空闲时间和过度拥挤之间的最佳点。
使用数据库它可以正常处理,尽管运行 10k 排队作业需要几个小时,但是使用 sqs 和 redis 我遇到了很多失败。
如果您将错误消息和任何其他相关信息添加到问题中,我将尝试更新此答案。
我很好奇 Laravel 缓存是否适用于队列系统。排队脚本的元素对于每次运行都是通用的,所以如果我从一开始就将数据排队,可能会节省一些时间。
我们当然可以在队列中执行作业时使用缓存 API。我们看到的任何性能改进都取决于为我们可以存储在缓存中的每个作业重现数据的成本。我不能肯定地说怎么多少时间缓存将节省,因为我不熟悉的项目,但你可以分析代码的部分作业找到昂贵的操作。
或者,我们可以在内存中缓存可重用的数据。当我们使用 初始化队列工作器时artisan queue:work
,Laravel 会启动一个 PHP 进程并为工作器执行的所有作业启动一次应用程序。这与典型 PHP Web 应用程序的应用程序生命周期不同,其中应用程序为每个请求重新启动并在每个请求结束时处理状态。因为每个作业都在同一个进程中执行,我们可以创建一个对象,将共享作业数据缓存在进程内存中,也许通过将单例绑定到 IoC 容器中,作业可以比 Redis 缓存存储更快地读取,因为我们避免从缓存后端获取数据所需的开销。
当然,这也意味着我们需要确保我们的作业不会泄漏内存,即使我们没有如上所述缓存数据。
我只是在阅读有关地平线的信息,我不确定它是否对这种情况有所帮助。
Horizon 提供了一项监控服务,可能有助于追踪此设置的问题。如果应用程序使用 Horizon 空闲时可以在其间分配工作的其他队列,它也可能会稍微提高效率,但问题似乎并未表明情况确实如此。
三个克隆中的每一个都具有以下工作器配置:
Run Code Online (Sandbox Code Playgroud)command=php /home/forge/default/artisan queue:work sqs --sleep=10 --daemon --quiet --timeout=30 --tries=3
(旁注:对于 Laravel 5.3 及更高版本,该--daemon
选项已弃用,queue:work
默认情况下该命令以守护进程模式运行。)