【发布时间】:2017-11-12 23:32:29
【问题描述】:
我正忙着将一个用 PHP/MySQL 编写的客户应用程序从 Hetzner 迁移到 AWS。一切正常,但有一些脚本。这些脚本写得很糟糕,循环数百万条记录,在每次循环运行中创建数百个局部变量,将每一行写入一个 excel 文件,打开另一个文件,写入状态更新并在每次循环运行中关闭一个文件.该脚本使用主 Web 应用程序中的 shell_exec 作为独立进程生成。
当我第一次在 EC2 上测试脚本时,它很快就崩溃了,因为我的 EC2 实例上的 php memory_limit 参数设置为 128M。该错误类似于以下错误:
Fatal error: Allowed memory size of X bytes exhausted (tried to allocate Y bytes)
我将memory_limit 从128M 增加到256M,然后增加到512M,然后增加到1024M、4096M,最终设置为-1,看看问题出在哪里。
将其设置为 -1 最初似乎可行,但随后冻结了整个实例 (t2.micro)。然后我意识到这是因为缺少交换空间而达到了系统内存限制,所以只是为了测试目的,我添加了一个交换空间4GB 并将memory_limit 设置为-1。这确实按预期工作,脚本从未崩溃,但随着脚本的运行,它变得越来越慢。例如,它将前 10% 的记录写入 excel 文件比 50% 后的 10% 快得多。所有这一切都是在我观察内存使用量扩展到 6 GB 的情况下进行的。
以下是脚本运行时htop 的屏幕截图:
我使用的是默认的php.ini,除了memory_limit,它设置为-1。
但是,当我在另一台服务器(本例中为 Hetzner 共享主机)上运行这个 非常 相同的脚本时,服务器以某种方式限制了内存使用,并且脚本在 @987654350 的 128M 上运行良好@ 环境。虽然这并不完全正确(正如服务器上的htop 所证实的那样),但它似乎不会在内存/交换空间比我的 EC2 实例上少得多的服务器上崩溃。
以下是在 Hetzner 上运行的 htop 的屏幕截图:
第三个屏幕截图是在脚本接近尾声时截取的 - 正如您所见,从开始到结束,内存并没有太大变化。这是来自服务器的php.ini 设置:
display_errors=1
memory_limit=128M
max_execution_time=90
max_input_vars=3500
upload_max_filesize=64M
post_max_size=64M
allow_url_fopen=0
数据库和代码库在这两种情况下都是完全相同的副本。两种情况下生成的 excel 文件大小约为 225MB。
那么,有什么想法可能导致这种行为,我应该如何在我的 EC2 实例上修复它?
感谢您的帮助!
【问题讨论】:
-
您能做的最好的事情就是让脚本更有效率。 Hetzner 实例也使用了大约 5G 的内存,因此该服务器上的 php.ini 肯定也有覆盖。
-
不确定我是否遗漏了某些内容,但 Hetzner 实例并未仅将 5 GB 用于脚本。就像我说的,它是一个共享实例,您看到的
4686/15964MB是服务器上运行的所有 帐户/进程(不仅仅是我的)的内存使用情况。如果您查看 EC2 和 Hetzner 屏幕截图中 PHP 脚本的 VIRT 和 RES 列 - 在消耗的内存方面似乎存在巨大差异。 -
是的,对不起,我看错了,Hetzner 服务器是虚拟化的还是物理的?
-
不用担心。它是一个“共享”托管包 - 但它看起来像是在多个用户/客户之间共享的物理服务器(不是虚拟机)。我已经给他们发了一封电子邮件来澄清。
-
我提出的 2 条建议是:比较两台服务器之间的 php 版本和安装的扩展,并优化 PHP 脚本以在使用变量完成时释放内存。
标签: php apache amazon-web-services amazon-ec2 amazon-aurora