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