Question Pourquoi les applications d'un conteneur LXC limité en mémoire écrivant des fichiers volumineux sur le disque sont-elles tuées par le MOO?


EDIT2: Ce problème semble également exister sous SMP 3.8.0-25-generic # 37-Ubuntu

EDIT: J'ai modifié la question du titre original de "Pourquoi le gestionnaire Linux Out of Memory serait-il déclenché en écrivant dans un fichier avec dd?" pour mieux refléter mon inquiétude face au problème général décrit ci-dessous:

Je suis dans un scénario gênant où le tueur de MOO est difficile élimination des processus dans mon conteneur LXC lorsque j'écris un fichier dont la taille dépasse la limite de mémoire (définie sur 300 Mo). Le problème ne se produit pas lorsque j'exécute l'application sur une machine virtuelle Xen (une EC2 t1.micro) qui ne dispose en réalité que de 512 Mo de RAM. Il semble donc y avoir un problème avec la mise en mémoire tampon du fichier respectant la limite de mémoire des conteneurs.

À titre d’exemple simple, je peux démontrer qu’un fichier volumineux écrit par dd causera des problèmes. Encore une fois, ce problème affecte toutes les applications. Je cherche à résoudre le problème général de la taille excessive du cache de l'application; Je comprends comment je peux faire fonctionner le "dd".

Scénario:

J'ai un conteneur LXC où memory.limit_in_bytes est défini sur 300 Mo.

J'essaie de créer un fichier de ~ 500 Mo comme suit:

dd if=/dev/zero of=test2 bs=100k count=5010

Environ 20% du temps, le gestionnaire de MOO Linux est déclenché par cette commande et un processus est tué. Inutile de dire que ceci est hautement involontaire comportement; dd est conçu pour simuler une écriture de fichier "utile" par un programme en cours d'exécution à l'intérieur du conteneur.

Détails: Alors que les caches de fichiers deviennent volumineux (260 Mo), les fichiers rss et les mappes de fichiers semblent rester assez faible. Voici un exemple de ce à quoi peut ressembler memory.stat lors de l'écriture:

cache 278667264
rss 20971520
mapped_file 24576
pgpgin 138147
pgpgout 64993
swap 0
pgfault 55054
pgmajfault 2
inactive_anon 10637312
active_anon 10342400
inactive_file 278339584
active_file 319488
unevictable 0
hierarchical_memory_limit 300003328
hierarchical_memsw_limit 300003328
total_cache 278667264
total_rss 20971520
total_mapped_file 24576
total_pgpgin 138147
total_pgpgout 64993
total_swap 0
total_pgfault 55054
total_pgmajfault 2
total_inactive_anon 10637312
total_active_anon 10342400
total_inactive_file 278339584
total_active_file 319488
total_unevictable 0

Voici une pâte de dmesg où le MOO a déclenché une mise à mort. Je ne suis pas trop familiariser avec les distinctions entre les types de mémoire; une chose qui se distingue par le fait que, si le "nœud 0 normal" est très bas, il y a beaucoup de Nœud 0 DMA32 libre de mémoire. Quelqu'un peut-il expliquer pourquoi l'écriture d'un fichier est la cause le MOO? Comment puis-je empêcher que cela se produise?

Le journal:

[1801523.686755] Task in /lxc/c-7 killed as a result of limit of /lxc/c-7
[1801523.686758] memory: usage 292972kB, limit 292972kB, failcnt 39580
[1801523.686760] memory+swap: usage 292972kB, limit 292972kB, failcnt 0
[1801523.686762] Mem-Info:
[1801523.686764] Node 0 DMA per-cpu:
[1801523.686767] CPU    0: hi:    0, btch:   1 usd:   0
[1801523.686769] CPU    1: hi:    0, btch:   1 usd:   0
[1801523.686771] CPU    2: hi:    0, btch:   1 usd:   0
[1801523.686773] CPU    3: hi:    0, btch:   1 usd:   0
[1801523.686775] CPU    4: hi:    0, btch:   1 usd:   0
[1801523.686778] CPU    5: hi:    0, btch:   1 usd:   0
[1801523.686780] CPU    6: hi:    0, btch:   1 usd:   0
[1801523.686782] CPU    7: hi:    0, btch:   1 usd:   0
[1801523.686783] Node 0 DMA32 per-cpu:
[1801523.686786] CPU    0: hi:  186, btch:  31 usd: 158
[1801523.686788] CPU    1: hi:  186, btch:  31 usd: 114
[1801523.686790] CPU    2: hi:  186, btch:  31 usd: 133
[1801523.686792] CPU    3: hi:  186, btch:  31 usd:  69
[1801523.686794] CPU    4: hi:  186, btch:  31 usd:  70
[1801523.686796] CPU    5: hi:  186, btch:  31 usd: 131
[1801523.686798] CPU    6: hi:  186, btch:  31 usd: 169
[1801523.686800] CPU    7: hi:  186, btch:  31 usd:  30
[1801523.686802] Node 0 Normal per-cpu:
[1801523.686804] CPU    0: hi:  186, btch:  31 usd: 162
[1801523.686806] CPU    1: hi:  186, btch:  31 usd: 184
[1801523.686809] CPU    2: hi:  186, btch:  31 usd:  99
[1801523.686811] CPU    3: hi:  186, btch:  31 usd:  82
[1801523.686813] CPU    4: hi:  186, btch:  31 usd:  90
[1801523.686815] CPU    5: hi:  186, btch:  31 usd:  99
[1801523.686817] CPU    6: hi:  186, btch:  31 usd: 157
[1801523.686819] CPU    7: hi:  186, btch:  31 usd: 138
[1801523.686824] active_anon:60439 inactive_anon:28841 isolated_anon:0
[1801523.686825]  active_file:110417 inactive_file:907078 isolated_file:64
[1801523.686827]  unevictable:0 dirty:164722 writeback:1652 unstable:0
[1801523.686828]  free:445909 slab_reclaimable:176594
slab_unreclaimable:14754
[1801523.686829]  mapped:4753 shmem:66 pagetables:3600 bounce:0
[1801523.686831] Node 0 DMA free:7904kB min:8kB low:8kB high:12kB
active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB
unevictable:0kB isolated(anon):0kB isolated(file):0kB present:7648kB
mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB
slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB
unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0
all_unreclaimable? no
[1801523.686841] lowmem_reserve[]: 0 4016 7048 7048
[1801523.686845] Node 0 DMA32 free:1770072kB min:6116kB low:7644kB
high:9172kB active_anon:22312kB inactive_anon:12128kB active_file:4988kB
inactive_file:2190136kB unevictable:0kB isolated(anon):0kB
isolated(file):256kB present:4112640kB mlocked:0kB dirty:535072kB
writeback:6452kB mapped:4kB shmem:4kB slab_reclaimable:72888kB
slab_unreclaimable:1100kB kernel_stack:120kB pagetables:832kB unstable:0kB
bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[1801523.686855] lowmem_reserve[]: 0 0 3031 3031
[1801523.686859] Node 0 Normal free:5660kB min:4616kB low:5768kB
high:6924kB active_anon:219444kB inactive_anon:103236kB
active_file:436680kB inactive_file:1438176kB unevictable:0kB
isolated(anon):0kB isolated(file):0kB present:3104640kB mlocked:0kB
dirty:123816kB writeback:156kB mapped:19008kB shmem:260kB
slab_reclaimable:633488kB slab_unreclaimable:57916kB kernel_stack:2800kB
pagetables:13568kB unstable:0kB bounce:0kB writeback_tmp:0kB
pages_scanned:0 all_unreclaimable? no
[1801523.686869] lowmem_reserve[]: 0 0 0 0
[1801523.686873] Node 0 DMA: 2*4kB 3*8kB 0*16kB 2*32kB 4*64kB 3*128kB
2*256kB 1*512kB 2*1024kB 2*2048kB 0*4096kB = 7904kB
[1801523.686883] Node 0 DMA32: 129*4kB 87*8kB 86*16kB 89*32kB 87*64kB
65*128kB 12*256kB 5*512kB 2*1024kB 13*2048kB 419*4096kB = 1769852kB
[1801523.686893] Node 0 Normal: 477*4kB 23*8kB 1*16kB 5*32kB 0*64kB 3*128kB
3*256kB 1*512kB 0*1024kB 1*2048kB 0*4096kB = 5980kB
[1801523.686903] 1017542 total pagecache pages
[1801523.686905] 0 pages in swap cache
[1801523.686907] Swap cache stats: add 0, delete 0, find 0/0
[1801523.686908] Free swap  = 1048572kB
[1801523.686910] Total swap = 1048572kB
[1801523.722319] 1837040 pages RAM
[1801523.722322] 58337 pages reserved
[1801523.722323] 972948 pages shared
[1801523.722324] 406948 pages non-shared
[1801523.722326] [ pid ]   uid  tgid total_vm      rss cpu oom_adj
oom_score_adj name
[1801523.722396] [31266]     0 31266     6404      511   6       0
    0 init
[1801523.722445] [32489]     0 32489    12370      688   7     -17
-1000 sshd
[1801523.722460] [32511]   101 32511    10513      325   0       0
    0 rsyslogd
[1801523.722495] [32625]     0 32625    17706      838   2       0
    0 sshd
[1801523.722522] [32652]   103 32652     5900      176   0       0
    0 dbus-daemon
[1801523.722583] [  526]     0   526     1553      168   5       0
    0 getty
[1801523.722587] [  530]     0   530     1553      168   1       0
    0 getty
[1801523.722593] [  537]  2007   537    17706      423   5       0
    0 sshd
[1801523.722629] [  538]  2007   538    16974     5191   1       0
    0 python
[1801523.722650] [  877]  2007   877     2106      157   7       0
    0 dd
[1801523.722657] Memory cgroup out of memory: Kill process 538 (python)
score 71 or sacrifice child
[1801523.722674] Killed process 538 (python) total-vm:67896kB,
anon-rss:17464kB, file-rss:3300kB

Je suis sous Linux ip-10-8-139-98 3.2.0-29-virtual # 46-Ubuntu SMP ven. Juil. 27 17:23:50 UTC 2012 x86_64 x86_64 x86_64 GNU / Linux sur Amazon EC2.


10
2018-06-15 15:35


origine


En résumé, il s’agit d’un bogue du noyau Linux. - UsAaR33


Réponses:


Edit: Je garderai ma réponse originale ci-dessous, mais je tenterai d'expliquer ce qui se passe ici et de vous proposer une solution générale.

Edit 2: Fourni une autre option.

Le problème que vous rencontrez ici est lié à la façon dont le noyau gère les E / S. Lorsque vous effectuez une écriture sur votre système de fichiers, cette écriture n'est pas immédiatement validée sur le disque; ce serait incroyablement inefficace. Au lieu de cela, les écritures sont mises en cache dans une zone de mémoire appelée cache de page, et périodiquement écrites en morceaux sur le disque. La section "sale" de votre journal décrit la taille de ce cache de page qui n'a pas encore été écrit sur le disque:

dirty:123816kB

Alors, qu'est-ce qui vide ce cache sale? Pourquoi ne fait-il pas son travail?

«Flush» sous Linux est responsable de l'écriture des pages non conformes sur le disque. C'est un démon qui se réveille périodiquement pour déterminer si des écritures sont requises sur le disque et, le cas échéant, les effectuer. Si vous êtes un type de gars C, commencez ici. Flush est incroyablement efficace. il fait un excellent travail de vidage des choses sur le disque en cas de besoin. Et cela fonctionne exactement comme il est supposé.

Pistes affleurantes à l'extérieur de votre conteneur LXC, car votre conteneur LXC ne possède pas son propre noyau. Les conteneurs LXC existent en tant que construction autour de cgroups, qui est une fonctionnalité du noyau Linux qui permet de mieux limiter et isoler les groupes de processus, mais pas son propre démon noyau ou flush.

Etant donné que votre LXC a une limite de mémoire inférieure à celle du noyau, des choses étranges se produisent. Flush suppose qu’il a toute la mémoire de l’hôte dans lequel le cache est écrit. Un programme de votre LXC commence à écrire un fichier volumineux, il tamponne ... des tampons ... et finit par atteindre sa limite absolue, puis appelle le gestionnaire de MOO. Ce n'est pas un échec d'un composant particulier; c'est le comportement attendu. Genre de. Ce genre de chose devrait être gérée par les groupes de contrôle, mais cela ne semble pas être le cas.

Ceci explique complètement le comportement que vous voyez entre les tailles d'instances. Vous commencerez à vider le disque beaucoup plus tôt sur la micro-instance (avec 512 Mo de RAM) que sur une grande instance

Ok, ça a du sens. Mais c'est inutile. J'ai encore besoin de m'écrire un gros fichier.

Eh bien, flush n'est pas au courant de votre limite LXC. Donc au lieu de patcher le noyau, il y a quelques options ici pour des choses que vous pouvez essayer de modifier:

/proc/sys/vm/dirty_expire_centiseconds

Ceci contrôle la durée pendant laquelle une page peut être conservée dans le cache modifié et écrite sur le disque. Par défaut, c'est 30 secondes. essayez de le baisser pour commencer à pousser plus vite.

/proc/sys/vm/dirty_background_ratio

Ceci contrôle le pourcentage de vidage mémoire actif autorisé à se remplir avant qu'il ne commence à forcer les écritures. Il y a un peu de bidouillage qui va dans le tri de la total exact Ici, mais l'explication la plus simple est de simplement regarder votre mémoire totale. Par défaut, c'est 10% (sur certaines distributions, 5%). Réglez ceci plus bas; cela forcera les écritures sur le disque plus tôt et empêchera votre LXC de dépasser ses limites.

Je ne peux pas simplement visser le système de fichiers un peu?

Ben ouais. Mais assurez-vous de tester ceci .. vous pourriez affecter les performances. Sur vos supports dans / etc / fstab où vous écrirez ceci, ajoutez le 'synchroniser'option de montage.

Réponse originale:

Essayez de réduire la taille de bloc utilisée par DD:

dd if=/dev/zero of=test2 bs=512 count=1024000

Vous ne pouvez écrire qu'un secteur à la fois (512 octets sur des disques durs plus anciens, 4096   sur plus récent). Si DD pousse les écritures sur le disque plus vite que le disque ne le peut   les accepter, il commencera à mettre en cache les écritures en mémoire. C'est pourquoi   votre cache de fichiers s'agrandit.


13
2018-06-15 19:08



Je dois noter que si j'exécute des tests similaires en python où je vide manuellement l'objet fichier, l'erreur se produit toujours avec une probabilité similaire. La mémoire cache s'agrandit bien sûr, mais cela devrait être purgé, plutôt que de tuer le processus. - UsAaR33
Je donnerais un coup quand même. J'ai trouvé que forcer fsync () avec Python ne répondait pas toujours à vos attentes. - alexphilipp
@ UsAaR33 Obtenez un disque plus rapide. - tink
@ UsAaR33 Une application écrira le plus rapidement possible. il s'attend à ce que le noyau gère l'IO. Je n'ai jamais utilisé de conteneur LXC auparavant, mais d'un simple coup d'œil, il semble qu'il ne fournisse pas son propre noyau dans le chroot qu'il crée? Si tel est le cas, le noyau fournit à IO l'hypothèse selon laquelle il dispose de toute la mémoire du système hôte. Il n’a aucune idée que vous estimez le limiter à 300 Mo. Une fois cette limite atteinte, le MOO commence à tuer les processus. - alexphilipp
@ UsAaR33: des paramètres incorrects entraînent de mauvais résultats. On dit qu'une partie du système permet d'utiliser beaucoup de mémoire en tant que cache, tandis qu'une autre partie du système doit tuer les processus si le cache est trop volumineux. Pourquoi devrait-il attendre le disque alors qu'il y a beaucoup de RAM disponible? Et s'il y a beaucoup de RAM disponible, pourquoi ne pas le laisser l'utiliser? - David Schwartz


Votre fichier est-il écrit dans / tmp? Si tel est le cas, il se peut que ce ne soit pas sur un système de fichiers réel mais résidant sur le disque. Ainsi, à mesure que vous écrivez, de plus en plus de mémoire est supprimée pour répondre aux besoins du fichier. Finalement, vous manquez de mémoire + d'espace d'échange et vos performances se détériorent au point de provoquer une frustration totale.


3
2018-06-15 17:38



Il écrit sur $ HOME, qui se trouve sur un montage AUFS qui déclenche des écritures sur le disque sous-jacent. (EC2 EBS) - UsAaR33


sauf si vous écrivez sur un disque virtuel, vous pouvez éviter la mise en cache en utilisant oflag = direct

dd if=/dev/zero of=test2 bs=100k oflag=direct count=5010

2
2018-06-16 06:42



direct provoque une erreur "Invalid argument", mais l'utilisation de oflag = dsync fonctionne. - UsAaR33
Je suis désolé si cela n'a pas fonctionné pour vous, comme indiqué dans la page de manuel "Utilisation directe des E / S directes pour les données" - Kevin Parker