異常高的 dentry 記憶體使用率
問題
幾天前,一台核心為 2.6.32 和 128 GB 物理 RAM 的 CentOS 機器遇到了麻煩。負責的系統管理員告訴我,PHP-FPM 應用程序由於交換而無法及時響應請求,並且看到
free
幾乎沒有剩餘記憶體,他選擇重新啟動機器。我知道空閒記憶體在 Linux 上可能是一個令人困惑的概念,重新啟動可能是錯誤的做法。然而,上述管理員指責 PHP 應用程序(我負責)並拒絕進一步調查。
我自己能發現的是:
- 在重新啟動之前,可用記憶體(包括緩衝區和記憶體)只有幾百 MB。
- 在重新啟動之前,
/proc/meminfo
報告了大約 90 GB 的 Slab 記憶體使用量(是的,GB)。- 重新啟動後,可用記憶體為 119 GB,在一小時內下降到大約 100 GB,因為 PHP-FPM 工作人員(其中大約 600 個)恢復了生命,每個工作人員在 30 到 40 MB 之間顯示頂部的 RES 列(這種方式已經持續了幾個月,考慮到 PHP 應用程序的性質,這是完全合理的)。程序列表中沒有其他內容會消耗異常或值得注意的 RAM 量。
- 重啟後,Slab 記憶體在 300 MB 左右
從那以後一直在監視系統,最值得注意的是,Slab 記憶體以每天約 5 GB 的速度直線增長。報告的可用記憶體
free
並/proc/meminfo
以相同的速率減少。Slab 目前為 46 GB。根據slabtop
大部分用於dentry
條目:空閒記憶體:
free -m total used free shared buffers cached Mem: 129048 76435 52612 0 144 7675 -/+ buffers/cache: 68615 60432 Swap: 8191 0 8191
記憶體資訊:
cat /proc/meminfo MemTotal: 132145324 kB MemFree: 53620068 kB Buffers: 147760 kB Cached: 8239072 kB SwapCached: 0 kB Active: 20300940 kB Inactive: 6512716 kB Active(anon): 18408460 kB Inactive(anon): 24736 kB Active(file): 1892480 kB Inactive(file): 6487980 kB Unevictable: 8608 kB Mlocked: 8608 kB SwapTotal: 8388600 kB SwapFree: 8388600 kB Dirty: 11416 kB Writeback: 0 kB AnonPages: 18436224 kB Mapped: 94536 kB Shmem: 6364 kB Slab: 46240380 kB SReclaimable: 44561644 kB SUnreclaim: 1678736 kB KernelStack: 9336 kB PageTables: 457516 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 72364108 kB Committed_AS: 22305444 kB VmallocTotal: 34359738367 kB VmallocUsed: 480164 kB VmallocChunk: 34290830848 kB HardwareCorrupted: 0 kB AnonHugePages: 12216320 kB HugePages_Total: 2048 HugePages_Free: 2048 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 5604 kB DirectMap2M: 2078720 kB DirectMap1G: 132120576 kB
平板:
slabtop --once Active / Total Objects (% used) : 225920064 / 226193412 (99.9%) Active / Total Slabs (% used) : 11556364 / 11556415 (100.0%) Active / Total Caches (% used) : 110 / 194 (56.7%) Active / Total Size (% used) : 43278793.73K / 43315465.42K (99.9%) Minimum / Average / Maximum Object : 0.02K / 0.19K / 4096.00K OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME 221416340 221416039 3% 0.19K 11070817 20 44283268K dentry 1123443 1122739 99% 0.41K 124827 9 499308K fuse_request 1122320 1122180 99% 0.75K 224464 5 897856K fuse_inode 761539 754272 99% 0.20K 40081 19 160324K vm_area_struct 437858 223259 50% 0.10K 11834 37 47336K buffer_head 353353 347519 98% 0.05K 4589 77 18356K anon_vma_chain 325090 324190 99% 0.06K 5510 59 22040K size-64 146272 145422 99% 0.03K 1306 112 5224K size-32 137625 137614 99% 1.02K 45875 3 183500K nfs_inode_cache 128800 118407 91% 0.04K 1400 92 5600K anon_vma 59101 46853 79% 0.55K 8443 7 33772K radix_tree_node 52620 52009 98% 0.12K 1754 30 7016K size-128 19359 19253 99% 0.14K 717 27 2868K sysfs_dir_cache 10240 7746 75% 0.19K 512 20 2048K filp
VFS 記憶體壓力:
cat /proc/sys/vm/vfs_cache_pressure 125
交換性:
cat /proc/sys/vm/swappiness 0
我知道未使用的記憶體是浪費的記憶體,所以這不一定是一件壞事(特別是考慮到 44 GB 顯示為 SReclaimable)。然而,顯然這台機器還是遇到了問題,恐怕幾天后 Slab 超過 90 GB 時會再次發生同樣的情況。
問題
我有這些問題:
- 我認為 Slab 記憶體始終是物理 RAM 並且已經從 MemFree 值中減去該數字是否正確?
- 這麼多的dentry條目是正常的嗎?PHP 應用程序可以訪問大約 150 萬個文件,但其中大部分是存檔文件,根本無法訪問正常 Web 流量。
- 記憶體 inode 的數量遠低於記憶體的 dentry 的數量這一事實可能是什麼解釋,它們不應該以某種方式相關嗎?
- 如果系統遇到記憶體問題,核心不應該自動釋放一些dentries嗎?沒有發生這種情況的原因可能是什麼?
- 有沒有辦法“查看”dentry 記憶體以查看所有這些記憶體是什麼(即正在記憶體的路徑是什麼)?也許這指向某種記憶體洩漏、符號連結循環,或者確實是 PHP 應用程序做錯了什麼。
- PHP 應用程式碼以及所有資產文件都是通過 GlusterFS 網路文件系統掛載的,這可能與它有關嗎?
請記住,我不能以 root 身份進行調查,只能以普通使用者身份進行調查,並且管理員拒絕提供幫助。他甚至不會執行典型的
echo 2 > /proc/sys/vm/drop_caches
測試來查看 Slab 記憶體是否確實可回收。任何對可能發生的事情以及我如何進一步調查的見解將不勝感激。
更新
一些進一步的診斷資訊:
坐騎:
cat /proc/self/mounts rootfs / rootfs rw 0 0 proc /proc proc rw,relatime 0 0 sysfs /sys sysfs rw,relatime 0 0 devtmpfs /dev devtmpfs rw,relatime,size=66063000k,nr_inodes=16515750,mode=755 0 0 devpts /dev/pts devpts rw,relatime,gid=5,mode=620,ptmxmode=000 0 0 tmpfs /dev/shm tmpfs rw,relatime 0 0 /dev/mapper/sysvg-lv_root / ext4 rw,relatime,barrier=1,data=ordered 0 0 /proc/bus/usb /proc/bus/usb usbfs rw,relatime 0 0 /dev/sda1 /boot ext4 rw,relatime,barrier=1,data=ordered 0 0 tmpfs /phptmp tmpfs rw,noatime,size=1048576k,nr_inodes=15728640,mode=777 0 0 tmpfs /wsdltmp tmpfs rw,noatime,size=1048576k,nr_inodes=15728640,mode=777 0 0 none /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0 cgroup /cgroup/cpuset cgroup rw,relatime,cpuset 0 0 cgroup /cgroup/cpu cgroup rw,relatime,cpu 0 0 cgroup /cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0 cgroup /cgroup/memory cgroup rw,relatime,memory 0 0 cgroup /cgroup/devices cgroup rw,relatime,devices 0 0 cgroup /cgroup/freezer cgroup rw,relatime,freezer 0 0 cgroup /cgroup/net_cls cgroup rw,relatime,net_cls 0 0 cgroup /cgroup/blkio cgroup rw,relatime,blkio 0 0 /etc/glusterfs/glusterfs-www.vol /var/www fuse.glusterfs rw,relatime,user_id=0,group_id=0,default_permissions,allow_other,max_read=131072 0 0 /etc/glusterfs/glusterfs-upload.vol /var/upload fuse.glusterfs rw,relatime,user_id=0,group_id=0,default_permissions,allow_other,max_read=131072 0 0 sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0 172.17.39.78:/www /data/www nfs rw,relatime,vers=3,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,port=38467,timeo=600,retrans=2,sec=sys,mountaddr=172.17.39.78,mountvers=3,mountport=38465,mountproto=tcp,local_lock=none,addr=172.17.39.78 0 0
掛載資訊:
cat /proc/self/mountinfo 16 21 0:3 / /proc rw,relatime - proc proc rw 17 21 0:0 / /sys rw,relatime - sysfs sysfs rw 18 21 0:5 / /dev rw,relatime - devtmpfs devtmpfs rw,size=66063000k,nr_inodes=16515750,mode=755 19 18 0:11 / /dev/pts rw,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000 20 18 0:16 / /dev/shm rw,relatime - tmpfs tmpfs rw 21 1 253:1 / / rw,relatime - ext4 /dev/mapper/sysvg-lv_root rw,barrier=1,data=ordered 22 16 0:15 / /proc/bus/usb rw,relatime - usbfs /proc/bus/usb rw 23 21 8:1 / /boot rw,relatime - ext4 /dev/sda1 rw,barrier=1,data=ordered 24 21 0:17 / /phptmp rw,noatime - tmpfs tmpfs rw,size=1048576k,nr_inodes=15728640,mode=777 25 21 0:18 / /wsdltmp rw,noatime - tmpfs tmpfs rw,size=1048576k,nr_inodes=15728640,mode=777 26 16 0:19 / /proc/sys/fs/binfmt_misc rw,relatime - binfmt_misc none rw 27 21 0:20 / /cgroup/cpuset rw,relatime - cgroup cgroup rw,cpuset 28 21 0:21 / /cgroup/cpu rw,relatime - cgroup cgroup rw,cpu 29 21 0:22 / /cgroup/cpuacct rw,relatime - cgroup cgroup rw,cpuacct 30 21 0:23 / /cgroup/memory rw,relatime - cgroup cgroup rw,memory 31 21 0:24 / /cgroup/devices rw,relatime - cgroup cgroup rw,devices 32 21 0:25 / /cgroup/freezer rw,relatime - cgroup cgroup rw,freezer 33 21 0:26 / /cgroup/net_cls rw,relatime - cgroup cgroup rw,net_cls 34 21 0:27 / /cgroup/blkio rw,relatime - cgroup cgroup rw,blkio 35 21 0:28 / /var/www rw,relatime - fuse.glusterfs /etc/glusterfs/glusterfs-www.vol rw,user_id=0,group_id=0,default_permissions,allow_other,max_read=131072 36 21 0:29 / /var/upload rw,relatime - fuse.glusterfs /etc/glusterfs/glusterfs-upload.vol rw,user_id=0,group_id=0,default_permissions,allow_other,max_read=131072 37 21 0:30 / /var/lib/nfs/rpc_pipefs rw,relatime - rpc_pipefs sunrpc rw 39 21 0:31 / /data/www rw,relatime - nfs 172.17.39.78:/www rw,vers=3,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,port=38467,timeo=600,retrans=2,sec=sys,mountaddr=172.17.39.78,mountvers=3,mountport=38465,mountproto=tcp,local_lock=none,addr=172.17.39.78
GlusterFS 配置:
cat /etc/glusterfs/glusterfs-www.vol volume remote1 type protocol/client option transport-type tcp option remote-host 172.17.39.71 option ping-timeout 10 option transport.socket.nodelay on # undocumented option for speed # http://gluster.org/pipermail/gluster-users/2009-September/003158.html option remote-subvolume /data/www end-volume volume remote2 type protocol/client option transport-type tcp option remote-host 172.17.39.72 option ping-timeout 10 option transport.socket.nodelay on # undocumented option for speed # http://gluster.org/pipermail/gluster-users/2009-September/003158.html option remote-subvolume /data/www end-volume volume remote3 type protocol/client option transport-type tcp option remote-host 172.17.39.73 option ping-timeout 10 option transport.socket.nodelay on # undocumented option for speed # http://gluster.org/pipermail/gluster-users/2009-September/003158.html option remote-subvolume /data/www end-volume volume remote4 type protocol/client option transport-type tcp option remote-host 172.17.39.74 option ping-timeout 10 option transport.socket.nodelay on # undocumented option for speed # http://gluster.org/pipermail/gluster-users/2009-September/003158.html option remote-subvolume /data/www end-volume volume replicate1 type cluster/replicate option lookup-unhashed off # off will reduce cpu usage, and network option local-volume-name 'hostname' subvolumes remote1 remote2 end-volume volume replicate2 type cluster/replicate option lookup-unhashed off # off will reduce cpu usage, and network option local-volume-name 'hostname' subvolumes remote3 remote4 end-volume volume distribute type cluster/distribute subvolumes replicate1 replicate2 end-volume volume iocache type performance/io-cache option cache-size 8192MB # default is 32MB subvolumes distribute end-volume volume writeback type performance/write-behind option cache-size 1024MB option window-size 1MB subvolumes iocache end-volume ### Add io-threads for parallel requisitions volume iothreads type performance/io-threads option thread-count 64 # default is 16 subvolumes writeback end-volume volume ra type performance/read-ahead option page-size 2MB option page-count 16 option force-atime-update no subvolumes iothreads end-volume
我認為 Slab 記憶體始終是物理 RAM 並且已經從 MemFree 值中減去該數字是否正確?
是的。
這麼多的dentry條目是正常的嗎?PHP 應用程序可以訪問大約 150 萬個文件,但其中大部分是存檔文件,根本無法訪問正常 Web 流量。
是的,如果系統沒有記憶體壓力。它必須將記憶體用於某些事情,並且在您的特定使用模式中,這可能是使用該記憶體的最佳方式。
記憶體 inode 的數量遠低於記憶體的 dentry 的數量這一事實可能是什麼解釋,它們不應該以某種方式相關嗎?
許多目錄操作將是最可能的解釋。
如果系統遇到記憶體問題,核心不應該自動釋放一些dentries嗎?沒有發生這種情況的原因可能是什麼?
它應該,而且我想不出任何它不會的原因。我不相信這實際上是錯誤的。我強烈建議您升級核心或進一步增加 vfs_cache_pressure。
有沒有辦法“查看”dentry 記憶體以查看所有這些記憶體是什麼(即正在記憶體的路徑是什麼)?也許這指向某種記憶體洩漏、符號連結循環,或者確實是 PHP 應用程序做錯了什麼。
我不相信有。我會尋找任何具有大量條目或搜尋或遍歷的非常深的目錄結構的目錄。
PHP 應用程式碼以及所有資產文件都是通過 GlusterFS 網路文件系統掛載的,這可能與它有關嗎?
絕對可能是文件系統問題。例如,一個文件系統錯誤導致不釋放dentries 是可能的。