选择正确的 CPU 和内存配置


以最有效的方式使用计算资源需要经历多次迭代,直到为每个用例找到最佳配置。

分配的资源少于需求,会遇到 CPU 负载高、队列堵塞、任务运行时间长、超时以及潜在的崩溃隐患等问题。

而分配的资源太多,则造成不必要的资源和财力浪费。

为你的用例找到理想的配置是一个很有挑战的工作,在这个系列中,我将给大家提供理论指导和实践过程中需要注意的事项。

一个专用的 vCPU

选择一个 2.7 GHz 的专用 vCPU(逻辑 CPU),即每秒可执行 2,700,000,000 个 CPU 周期(最小单位),每个指令都需要多个 CPU 周期完成。

以队列任务为例:

底层是一个无限循环:

虽然是一个无限循环,但是并不总是占用 CPU 周期,有时候还会等待来自其他服务的响应。比如以 Redis 驱动的队列,获取新任务时需要等待来自 Redis 服务器的响应数据。在此期间,CPU 周期可以被当前机器上的其他进程使用。

队列中也并不总是有任务,尽管如此,处理器进程也会一直保持和队列处理器的通信以便获取队列任务,这种持续不断的通信会让 CPU 一直处于繁忙状态,尽管队列是空的。

要避免这种情况,如果队列为空,可以这么做来暂停处理器:

在休眠的时间内,处理器可以执行其他指令。

还可以在命令选项中通过 --sleep 控制处理器阻塞的时间:

运行更多处理器进程

如果队列一直是满的,队列处理器会一直都在处理任务。处理器进程可以使用的 CPU 周期取决于运行的任务类型。

如果队列任务主要执行的是 CPU 密集型操作,那么处理器进程就可以尽可能利用所有可用的 CPU 周期,这将影响该服务器上其他进程的运行效率。不过,如果队列任务大部分时间都在等待(IO 密集型操作),那么队列处理器进程大部分时间都会处于闲置状态。

如果是 CPU 密集型任务,只能在 CPU 上运行一个处理器进程,该进程每次只能处理一个任务,这个时候任务处理速度取决于这台服务器 CPU 的性能。

如果是 IO 密集型任务,我们可以在这台单 CPU 服务器上启动多个处理器进程,这样一个进程处于闲置状态,其他进程就可以使用 CPU 周期执行任务。

这样一来,我们就可以充分利用 CPU 周期来提高队列任务处理速度。

添加更多 vCPU

扩展服务器拥有更多 vCPU 可以让你同时运行更多队列处理器进程以便更快地处理队列任务。启动的处理器进程数量依然取决于处理的任务类型。

如果启动的进程过多,会导致 CPU 使用率飙升至 100%,进而导致服务器挂起;如果扩展机器配置过多 vCPU,队列是可以更快的消费了,但是也费钱啊。

使用共享 vCPU

如果是在使用共享 CPU 的机器上,CPU 周期的利用率取决于邻近机器的负载,如果你与负载很重的机器共享 CPU,就无法充分利用 CPU。此外,如果你过多的使用 CPU,服务提供商也会给你发出警告,因为你正在试图将 CPU 占为己有。

对于一些低负载或者中等负载、偶尔会有一些高负载的机器,共享 CPU 是个不错的选择,它比配备专用 CPU 的机器要便宜,如果你还不确定自己想要什么样的 CPU,可以从这个选项开始。

选择合适的内存容量(RAM)

和选择 CPU 配置一样,选择机器的内存容量也需要考虑多个因素,并取决于队列任务的类型。

如果队列任务大部分时候需要很高的内存使用率,以至于你的机器经常触及内存上限,并开始交换到磁盘上,那么你就需要一台内存配置较大的服务器。

但是在扩展服务器之前,需要确保你的任务是干净的,鉴于一个 Laravel Worker 使用单一的守护进程,该进程用于处理所有从队列系统获取的任务,所以在扩展内存前需要确保内存中不包含运行中的任务。

如果一个处理器进程消耗掉了分配给 PHP 的所有内存,处理器进程会退出并报错,这种突发性的退出如果发生在队列任务处理过程中,会导致系统出现数据不一致。

为了避免这种情况,Laravel 默认为每个队列处理进程限定可以使用的内存上限是 128M,你可以通过 --memory 选项修改这个值:

php artisan queue:work --memory=256

注:这个处理器进程级别的设置优先级低于 PHP 配置文件 php.ini 中的 memory_limit 配置值。所以这里设置的限制不要高于 memory_limit

运行任务后,处理器会检查这个 PHP 进程使用的内存,如果触发上限,会退出进程。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 异步发送应用部署通知

>> 下一篇: 管理队列处理器进程和内存泄露问题