Pitchfork 占用内存过多吗?

有其他人也看到这种情况吗?这个论坛的规模和流量都相当适中。目前运行着四个 pitchfork 工作进程,看起来其中一个处理了绝大部分的传入请求,并且占用的内存也比其他进程多。系统中有大量交换空间(swap)被使用,而通过手动重启 pitchfork,内存占用会显著降低。因此我推断,pitchfork 进程目前有很多冷页面被交换到了磁盘上。

这是在运行了 20 天之后,机器配置为 4G 内存和 4G 交换空间。

如果交换空间耗尽那将是很糟糕的。同样糟糕的是,如果 pitchfork 最终执行垃圾回收时,发现大量的交换空间需要重新换入内存。

有人遇到过类似的情况吗?请分享你们的机器配置!

# ps aux | sort -n -k 4 | egrep pitchf\|MEM |tail
root     2167652  0.0  0.0   5912  1792 pts/0    S+   20:07   0:00 grep -E --color=auto pitchf|MEM
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000       15094  0.0  0.2 497544 10988 ?        Sl   Jul28   0:17 pitchfork monitor - 
1000       15704  0.0  2.5 6799124 97836 ?       Sl   Jul28   1:00 pitchfork (gen:0) service - ready
1000       15097  0.0  4.8 6791252 189724 ?      Sl   Jul28   5:26 pitchfork (gen:0) mold - ready
1000       15959  0.0  8.1 6815508 319708 ?      Sl   Jul28  12:05 pitchfork (gen:0) worker[3] - requests: 6684, waiting
1000       15900  0.0  9.2 6864596 360696 ?      Sl   Jul28  17:43 pitchfork (gen:0) worker[2] - requests: 14756, waiting
1000       15795  0.1 10.3 6884756 405420 ?      Sl   Jul28  48:36 pitchfork (gen:0) worker[1] - requests: 97007, waiting
1000       15734  2.1 12.8 11299708 500120 ?     Sl   Jul28 637:50 pitchfork (gen:0) worker[0] - requests: 2229848, waiting

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1874636       98840      678812     1931492     1160916
Swap:        4194288     1226600     2967688


# vmstat 5 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0 1226600 115820  65288 1866284    1    1    20    38    0    3  3  1 97  0  0
 0  0 1226600 113208  65296 1866296    0    0     0    14  411  478  1  1 98  0  0
 0  0 1226600 112956  65304 1866336    0    0     1    23  438  528  2  1 97  0  0
 0  0 1226600 112704  65308 1866360    0    0     1    31  518  603  5  1 94  0  0
 0  0 1226600 112704  65308 1866364    0    0     0    11  347  387  1  1 98  0  0

vmstat 的输出显示目前并没有内存压力——没有分页活动。我担心的是潜在的危险,而不是说我的安装目前运行得很糟糕。

cpu0

说点正经的,那个承担了所有工作的进程,其 RSS 内存占用仅仅比平均值高出 100MB?在我看来这很正常,还是我漏掉了什么?

我很想看看更繁忙的论坛的统计数据。看起来请求的累计数量很重要,而我的论坛远算不上繁忙。

是的,RSS 的差异相对温和,但从 300M 到 500M,在比例上还是有相当大的差距的。

更引人注目的是交换空间(swap)的使用情况。在挥舞干草叉之前,我看到:

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1888140       77308      679004     1939520     1147220
Swap:        4194288     1226344     2967944

回收之后:

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1486412     1422380      640744      996176     1587908
Swap:        4194288      309892     3884396

在我看来,通过回收释放了 1300M(used+swap 的差值)。

我认为在使用 unicorn 时并没有看到需要这么多交换空间:因此有了这个标题。

正如我所说,我对看到其他实例的数字很感兴趣。

一个 pitchfork 进程承担大部分负载是正常的——只有当第一个进程繁忙时,才会选择其他进程。内存随时间增长也是正常的。尽管在缓存/Ruby JIT 等一切完成预热后,内存最终应该会达到稳定状态。

这是我们一个生产集群在 7 天周期内的图表。它跟踪的是内存使用量最高的那个进程。绿色虚线表示部署(即 pitchfork 的新启动):

因此你可以看到,在初始启动后内存确实会增长,但随后稳定在略低于 1.4GB 的水平。由于该集群正在为数百个站点提供服务,所以在具体数值方面可能不是最好的比较对象……但希望这个增长过程的可视化展示会有所帮助。

仅查看每个进程的 RSS 数值并不能反映全貌。Pitchfork 是一个“forking web server”(通过 fork 创建工作进程的 Web 服务器)。它会启动“模具”(mold)进程,然后所有工作进程都通过写时复制(copy-on-write)内存模式从该进程 fork 而来。因此,虽然 worker[0] 的 RSS 可能显示为 500mb,但其中约 200mb 是与模具进程及其他所有工作进程共享的。

在不远的将来,我们希望启用 Pitchfork 的 “reforking” 功能。它会定期终止工作进程,并从已预热的工作进程中重新 fork 它们,以便它们随时间推移尽可能多地共享内存。不过,我们需要做一些工作来确保我们的所有代码都与这种模式兼容 :crossed_fingers:

很有用的可视化,谢谢。我不会说它已经完全稳定下来,但增长率确实没有之前那么高了。

定期重新分叉听起来是个很好的改进——如果可以的话,请在那项功能落地时在这里注明一下。

你能说说那些绿色线条代表什么吗?我想知道(如果有的话)分叉何时会执行垃圾回收、是什么触发了它,以及它在执行过程中会产生什么影响。

绿色线条表示我们部署更新的时间。基本上就是执行:./launcher rebuild app

Ruby(以及我们在 Ruby 进程中通过 MiniRacer/v8 运行的 JS)在运行期间会不断进行垃圾回收,并且会响应操作系统的信号。因此,我认为手动执行任何操作都不会带来太大好处。

谢谢。我很想看看长期运行会怎么样——不过在一个相对频繁更新的服务器上,这一点很难看出来。就我而言,我等了20天,然后选择用 pitchfork 重启。这虽然给我提供了一些信息,但也把计时器重置了。