Uso excepcionalmente alto de cache de dentry

34

Problema

Uma máquina CentOS com kernel 2.6.32 e 128 GB de RAM física teve problemas alguns dias atrás. O administrador do sistema responsável me diz que o aplicativo PHP-FPM não estava mais respondendo às solicitações em tempo hábil devido à troca e, tendo visto freeque quase não havia mais memória, ele optou por reiniciar a máquina.

Eu sei que a memória livre pode ser um conceito confuso no Linux e uma reinicialização talvez tenha sido a coisa errada a se fazer. No entanto, o administrador mencionado culpa o aplicativo PHP (pelo qual sou responsável) e se recusa a investigar mais.

O que eu pude descobrir sozinho é o seguinte:

  • Antes do reinício, a memória livre (incluindo buffers e cache) era de apenas algumas centenas de MB.
  • Antes do reinício, /proc/meminfo relatava um uso de memória Slab de cerca de 90 GB (sim, GB).
  • Após o reinício, a memória livre era de 119 GB, diminuindo para cerca de 100 GB em uma hora, quando os funcionários do PHP-FPM (cerca de 600 deles) estavam voltando à vida, cada um mostrando entre 30 e 40 MB no Coluna RES no topo (que tem sido assim há meses e é perfeitamente razoável, dada a natureza do aplicativo PHP). Não há mais nada na lista de processos que consome uma quantidade incomum ou digna de nota de RAM.
  • Após o reinício, a memória Slab estava em torno de 300 MB

Se estiver monitorando o sistema desde então, e principalmente a memória Slab está aumentando em uma linha reta com uma taxa de cerca de 5 GB por dia. A memória livre é relatada freee /proc/meminfodiminui na mesma taxa. A laje está atualmente em 46 GB. De acordo com a slabtopmaioria, é usado para dentryentradas:

Memoria livre:

free -m
             total       used       free     shared    buffers     cached
Mem:        129048      76435      52612          0        144       7675
-/+ buffers/cache:      68615      60432
Swap:         8191          0       8191

Meminfo:

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:

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  

Pressão no cache do VFS:

cat /proc/sys/vm/vfs_cache_pressure
125

Swappiness:

cat /proc/sys/vm/swappiness
0

Eu sei que a memória não utilizada é memória desperdiçada, portanto isso não deve necessariamente ser uma coisa ruim (especialmente considerando que 44 GB são mostrados como SReclaimable). No entanto, aparentemente a máquina enfrentou problemas, e receio que o mesmo acontecerá novamente em alguns dias quando a Slab ultrapassar os 90 GB.

Questões

Eu tenho estas perguntas:

  • Estou correto ao pensar que a memória Slab é sempre RAM física e o número já está subtraído do valor MemFree?
  • Um número tão alto de entradas de dentista é normal? O aplicativo PHP tem acesso a arquivos de cerca de 1,5 M, no entanto, a maioria deles é arquivada e não está sendo acessada para tráfego regular na Web.
  • O que poderia ser uma explicação para o fato de o número de inodes em cache ser muito menor que o número de dentries em cache, eles não deveriam estar relacionados de alguma forma?
  • Se o sistema tiver problemas de memória, o kernel não deve liberar alguns dos dentries automaticamente? O que poderia ser uma razão para isso não acontecer?
  • Existe alguma maneira de "examinar" o cache do dentry para ver o que é toda essa memória (ou seja, quais são os caminhos que estão sendo armazenados em cache)? Talvez isso indique algum tipo de vazamento de memória, loop de ligação simbólica ou mesmo algo que o aplicativo PHP esteja fazendo de errado.
  • O código do aplicativo PHP, bem como todos os arquivos de ativos, são montados através do sistema de arquivos de rede GlusterFS, isso poderia ter algo a ver com isso?

Lembre-se de que não posso investigar como root, apenas como um usuário comum, e que o administrador se recusa a ajudar. Ele nem fará o echo 2 > /proc/sys/vm/drop_cachesteste típico para ver se a memória do Slab é realmente recuperável.

Qualquer ideia sobre o que poderia estar acontecendo e como eu posso investigar mais seria muito apreciada.

Atualizações

Algumas informações adicionais de diagnóstico:

Suportes:

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

Informações da montagem:

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

Configuração do 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
Wolfgang Stengel
fonte
Forneça a saída de cat /proc/self/mountse (talvez bastante longa) cat /proc/self/mountinfo.
Matthew Ife
@Fefe Atualizei a pergunta, ambas as saídas são anexadas.
Wolfgang Stengel
Meu sentimento aqui é provavelmente relacionado ao cache de dentição do NFS. Fora de interesse você pode correr cat /etc/nfsmount.conf. Você também possui algum diretório que contenha muitos arquivos em seu diretório imediato?
Matthew Ife
11
Bem, desde vfs_cache_pressure> 100, o kernel deve preferir recuperar a memória cache do dentrie. Isso pode ser facilmente um bug, o 2.6.32 é um kernel bastante antigo, mesmo com os patches de backport do RedHat. BTW, qual é a versão exata do kernel?
Po14
2
(Seu sysadmin soa terrível Isso nos dá um mau nome.)
ewwhite

Respostas:

14

Estou correto ao pensar que a memória Slab é sempre RAM física e o número já está subtraído do valor MemFree?

Sim.

Um número tão alto de entradas de dentista é normal? O aplicativo PHP tem acesso a arquivos de cerca de 1,5 M, no entanto, a maioria deles é arquivada e não está sendo acessada para tráfego regular na Web.

Sim, se o sistema não estiver sob pressão de memória. Ele precisa usar a memória para alguma coisa e é possível que, em seu padrão de uso específico, essa seja a melhor maneira de usar essa memória.

O que poderia ser uma explicação para o fato de o número de inodes em cache ser muito menor que o número de dentries em cache, eles não deveriam estar relacionados de alguma forma?

Muitas operações de diretório seriam a explicação mais provável.

Se o sistema tiver problemas de memória, o kernel não deve liberar alguns dos dentries automaticamente? O que poderia ser uma razão para isso não acontecer?

Deveria, e não consigo pensar em nenhum motivo que não faria. Não estou convencido de que foi isso que realmente deu errado. Eu sugiro atualizar o seu kernel ou aumentar ainda mais o vfs_cache_pressure.

Existe alguma maneira de "examinar" o cache do dentry para ver o que é toda essa memória (ou seja, quais são os caminhos que estão sendo armazenados em cache)? Talvez isso indique algum tipo de vazamento de memória, loop de ligação simbólica ou mesmo algo que o aplicativo PHP esteja fazendo de errado.

Eu não acredito que exista. Eu procuraria por qualquer diretório com um número absurdamente grande de entradas ou estruturas de diretório muito profundas que sejam pesquisadas ou percorridas.

O código do aplicativo PHP, bem como todos os arquivos de ativos, são montados através do sistema de arquivos de rede GlusterFS, isso poderia ter algo a ver com isso?

Definitivamente, pode ser um problema no sistema de arquivos. Um bug no sistema de arquivos que faz com que os dentries não sejam liberados, por exemplo, é uma possibilidade.

David Schwartz
fonte
Obrigado por responder minhas perguntas individualmente. A pressão do cache foi finalmente aumentada ainda mais e o aumento do cache do dentry parou.
Wolfgang Stengel
Ainda não consegui rastrear o programa responsável. Se descobrir mais, informarei novamente qualquer pessoa que tenha esse problema.
Wolfgang Stengel
11
Obrigado! O diretório grande (arquivos de 0,25 mil) foi totalmente a causa do problema no meu caso, sempre que algo interagia com ele, 2 GB de RAM desapareciam no cache.
Some Linux Nerd
20

Solução confirmada

Para quem pode encontrar o mesmo problema. Os caras do data center finalmente descobriram hoje. O culpado era uma biblioteca NSS (Network Security Services) empacotada com Libcurl. Uma atualização para a versão mais recente resolveu o problema.

Um relatório de bug que descreve os detalhes está aqui:

https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=1044666

Aparentemente, para determinar se algum caminho é local ou em uma unidade de rede, o NSS procurava um arquivo inexistente e media o tempo necessário para o sistema de arquivos relatar! Se você tiver um número grande o suficiente de solicitações de Curl e memória suficiente, essas solicitações serão todas armazenadas em cache e empilhadas.

Wolfgang Stengel
fonte
15

Encontrei exatamente esse problema e, embora Wolfgang esteja correto sobre a causa, faltam alguns detalhes importantes.

  • Esse problema afeta as solicitações SSL feitas com curl ou libcurl ou qualquer outro software que use o mozilla NSS para conexão segura. Solicitações não seguras não acionam o problema.

  • O problema não requer solicitações de curvatura simultâneas. O acúmulo de dentry ocorrerá desde que as chamadas de curvatura sejam frequentes o suficiente para superar os esforços do sistema operacional para recuperar a RAM.

  • a versão mais recente do NSS, 3.16.0, inclui uma correção para isso. no entanto, você não obtém a correção gratuitamente ao atualizar o NSS e não precisa atualizar todo o NSS. você só precisa atualizar o nss-softokn (que tem uma dependência necessária do nss-utils) no mínimo. e para obter o benefício, é necessário configurar a variável de ambiente NSS_SDB_USE_CACHE para o processo que está usando a libcurl. a presença dessa variável de ambiente é o que permite que as verificações dispendiosas de arquivos inexistentes sejam ignoradas.

FWIW, escrevi uma entrada de blog com um pouco mais de experiência / detalhes, caso alguém precise.

J. Paulding
fonte
Obrigado por um bom post no blog, mas gostaria de mencionar que o nss-softokn ainda não foi atualizado para a versão 3.16 no CentOS / RHEL. Provavelmente será corrigido na versão 6.6.
Strahinja Kustudic
11
Obrigado pela observação. Talvez a Amazon tenha saído à frente dessa (talvez até a nosso pedido?) Para seus contratos gerenciados. Nas versões mais antigas (3.14-3.15), você ainda obtém metade do benefício, definindo as variáveis ​​de ambiente apropriadas. Se você possui o know-how, poderá construir a v3.16 diretamente. Caso contrário, aumentar a pressão do cache e receber a ocorrência de CPU associada pode ser sua melhor aposta para obter um desempenho confiável.
J. Paulding
3
Isso é corrigido no Centos 6.6 com o nss-softokn-3.14.3-17
Strahinja Kustudic
11
Apenas para deixar claro para as pessoas que procuram uma solução rápida: você precisa atualizar o nss-softokenRPM E definir o NSS_SDB_USE_CACHE=YESenv var para que as chamadas https curl https parem de inundar seu cache de dentry.
Steve Kehlet
4

Consulte https://www.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.7/2.6.7-mm1/broken-out/vfs-shrinkage-tuning.patch

Existem números mostrando que você pode esperar uma recuperação notável da memória do dentry quando o vfs_cache_pressure estiver definido como um valor superior a 100. Portanto, 125 pode ser muito baixo para que isso aconteça no seu caso.

poige
fonte
Pelo que li, aumentar vfs_cache_pressureacima 100só faz sentido se você não tiver RAM suficiente para sua carga de trabalho. Nesse caso, ter um valor acima de 100 (por exemplo, 10000) liberará um pouco de RAM. Isso resultará em pior IO geral, no entanto.
Mikko Rantalainen 17/01/19
3

Não é realmente uma explicação para sua resposta, mas como usuário deste sistema, essas informações foram fornecidas:

cat /proc/meminfo
MemTotal:       132145324 kB
...
SReclaimable:   44561644 kB
SUnreclaim:      1678736 kB

É o suficiente para me dizer que este não é o seu problema e é responsabilidade do administrador do sistema fornecer uma explicação adequada.

Eu não quero parecer rude aqui, mas;

  • Você não possui informações específicas sobre o papel desse host.
  • Como o host deve priorizar os recursos está fora do seu escopo.
  • Você não está familiarizado ou teve alguma parte no design e implantação do armazenamento neste host.
  • Você não pode oferecer determinada saída do sistema, pois não é root.

É de sua responsabilidade os administradores de sistemas do sistema justificar ou resolver a anomalia de alocação de laje. Ou você não nos deu uma imagem completa de toda a saga que o levou a isso (que sinceramente não estou interessado) ou o administrador do sistema está se comportando de forma irresponsável e / ou incompetente da maneira que ele considera lidar com esse problema.

Sinta-se livre para dizer a ele que um estranho aleatório na internet pensa que ele não está levando suas responsabilidades a sério.

Matthew Ife
fonte