虚拟化系统下使用 hugepage 的 php-fpm7.1 mmap/munmap 操作非常缓慢。

8

我的php-fpm进程在Ubuntu 14.04 LTS上(Nginx服务器,MariaDB数据库)面临性能问题。

strace -f $(pidof php-fpm7.1 | sed 's/\([0-9]*\)/\-p \1/g')

给了我。
<... epoll_wait resumed> {}, 1, 1000) = 0
[pid 32533] epoll_wait(8, {}, 1, 103)   = 0
[pid 32533] epoll_wait(8,  <unfinished ...>
[pid 32535] mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd933fdd000
[pid 32535] munmap(0x7fd933fdd000, 2097152) = 0
[pid 32535] mmap(NULL, 4190208, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd933dde000
[pid 32535] munmap(0x7fd933dde000, 139264) = 0
[pid 32535] munmap(0x7fd934000000, 1953792) = 0
[pid 32535] madvise(0x7fd933e00000, 2097152, MADV_HUGEPAGE) = 0
[pid 32533] <... epoll_wait resumed> {}, 1, 897) = 0
[pid 32533] epoll_wait(8, {}, 1, 1000)  = 0
[pid 32533] epoll_wait(8, {}, 1, 1000)  = 0
[pid 32533] epoll_wait(8,  <unfinished ...>
[pid 32535] mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd933c00000
[pid 32535] madvise(0x7fd933c00000, 2097152, MADV_HUGEPAGE) = 0
[pid 32533] <... epoll_wait resumed> {}, 1, 1000) = 0
[pid 32533] epoll_wait(8, {}, 1, 1000)  = 0
[pid 32533] epoll_wait(8, {}, 1, 1000)  = 0
[pid 32533] epoll_wait(8, {}, 1, 1000)  = 0
[pid 32533] epoll_wait(8,  <unfinished ...>
[pid 32535] mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd933a00000
[pid 32535] madvise(0x7fd933a00000, 2097152, MADV_HUGEPAGE) = 0
[pid 32533] <... epoll_wait resumed> {}, 1, 1000) = 0
[pid 32533] epoll_wait(8,  <unfinished ...>
[pid 32535] open("/usr/share/zoneinfo/UTC", O_RDONLY) = 7
[pid 32535] fstat(7, {st_mode=S_IFREG|0644, st_size=118, ...}) = 0
[pid 32535] read(7, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
[pid 32535] lseek(7, 0, SEEK_SET)       = 0
[pid 32535] mmap(NULL, 118, PROT_READ, MAP_SHARED, 7, 0) = 0x7fd946835000
[pid 32535] close(7)                    = 0
[pid 32535] munmap(0x7fd946835000, 118) = 0
[pid 32535] pwrite(5, "_sf2_attributes|a:2:{s:14:\"_secu"..., 979, 0) = 979
[pid 32535] close(5)                    = 0
[pid 32535] mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd933200000
[pid 32535] madvise(0x7fd933200000, 2097152, MADV_HUGEPAGE) = 0

我尝试使用php-fpm7.0和PHPMod7.1,但是出现了相同的问题。

CPU使用率在处理少量数据的请求时达到了100%。

配置是默认的。

在一个复制的实例上,php5.6-fpm运行良好。

编辑:可能相关的PHP脚本一直在执行mmap/munmap

编辑:我尝试启用hugepages https://wiki.debian.org/Hugepages cat /proc/meminfo | grep Huge给了我以下结果:

AnonHugePages:    108544 kB
HugePages_Total:     512
HugePages_Free:      497
HugePages_Rsvd:       50
HugePages_Surp:        0
Hugepagesize:       2048 kB

但问题仍然存在。

编辑:我尝试启用/禁用OPCache,并设置opcache.huge_code_pages=0,但没有结果。在http://php.net/上没有关于hugepages的文档。


现在发生在Ubuntu 16.04 LTS上。 - Etienne Gautier
使用了什么虚拟化管理程序? - Wassim Dhif
你知道PHP是否直接调用mmap()/munmap(),还是通过malloc()/free()?如果是通过malloc()/free(),你可以尝试将M_MMAP_THRESHOLD环境变量设置为类似于4MB或8MB的等效值,这样进程就会使用“正常”的堆内存来处理你看到的2MB分配。有关详细信息,请参见mallopt()手册页面。 - Andrew Henle
@WassimDhif ESXI - Etienne Gautier
没错,谢谢你提供的信息。 - Etienne Gautier
显示剩余3条评论
3个回答

3
我不能完全确定我们是否面临相同的问题,但这是我在Stack Overflow搜索中找到的最接近问题。我的研究对象是一个拥有以下规格的虚拟机: CPU:16 RAM:16GB 操作系统:Ubuntu 16.04.4 LTS 容器:使用块设备的LXD和ZFS文件系统 PHP版本:7.1
我运行了一些包含MariaDB、Nginx和PHP-FPM 7.1的LXD容器。这些都是开发环境,所以服务器只会受到一些流量攻击。应用程序是基于Symfony框架构建的。
我注意到页面加载速度极慢。在开发模式下,我一直等待超过一分钟才能加载页面。我没有花太多时间来确认这一点,但CLI脚本也感觉非常缓慢。我尝试调整了各种PHP设置(realpath caches,opcache on/off/各种设置等),但没有什么作用。
我可以始终追踪到其中一个PHP-FPM进程的strace,并看到一个系统调用似乎很慢。所有其他调用都顺利进行,但它在进程的生命周期中很多次卡住了以下调用。
madvise(0x7f4dcca00000, 2097152, MADV_HUGEPAGE) = 0

长话短说,通过禁用THP,我成功地显著提高了该应用程序的性能。我在LXD主机上运行了以下命令,页面加载时间就像黑夜和白天一样不同。

sysctl -w vm.nr_hugepages=0
echo never > /sys/kernel/mm/transparent_hugepage/enabled

我知道Redis建议禁用THP,因为与写时复制相关的性能问题。我也知道ZFS文件系统也使用写时复制,所以这个问题可能是相关的吗?


我知道了!我不可能独自面对这个问题,这太大了。不幸的是,我不再在这个环境中工作了,恐怕我没有时间再现这种行为。顺便说一下,该应用程序也是使用Symfony构建的。 - Etienne Gautier
同样的问题,ZFS、LXC和Symfony。同时还有一个大型数据库和占用内存较多的Java应用程序在运行。在Linux 4.9和4.19上确认过。重启后大约需要1周才能出现。 - bhelm

1
当你执行时,方括号中选择的值是什么?
cat /sys/kernel/mm/transparent_hugepage/enabled 

请确保它是madvise(因为mmaps通过MADV_HUGEPAGE显式请求透明巨大页面)或始终如此。

下一步是查看您的内核是否没有忙于压缩页面(THP必须找到2MB的连续内存块以获得巨大页面,如果物理内存碎片化,则可能会很困难)。 请查看以下数字:

cat /proc/vmstat |grep compact

在跑步前后,它们有增长吗?
下一步是捕获您进程的内核堆栈部分:
cat /proc/YOUR_PROCESS_PID/stack

其他有用的命令包括:
cat /proc/buddyinfo

查看物理内存碎片化情况。找到最后两列。它们是2MB和4MB大小的空闲内存块。另一个:

cat /proc/pagetypeinfo

并查找不可移动的页面块。


谢谢回复,我还不能进行实际测试,但我会在能够时通知您。 - Etienne Gautier

0

在主机上禁用透明大页面支持对我有用:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

在我的情况下,问题发生在在ZFS后端的LXD容器中运行composer时。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接