L'utilisation de la mémoire de build d'Ember-cli risque l'échec (OOM) sur la taille d'instance minimale

Lors de la mise à niveau, la plus grande contrainte sur la mémoire (RAM+swap) est de loin lorsque le processus ‘ember’ s’exécute. Je pense que chaque fois que j’ai effectué une mise à jour, elle a été plus importante que la précédente, et elle approche de la limite, rendant impossible son exécution sur des ordinateurs de taille recommandée minimale.

Il serait peut-être bon d’examiner cela avant que cela ne échoue réellement. (J’espère que, pour des raisons de coût, la réponse ne sera pas d’augmenter la taille minimale recommandée. Augmenter le swap aiderait, si l’espace disque le permet. En principe, on pourrait migrer temporairement vers une instance plus coûteuse avec plus de RAM.)

J’exécute deux forums de taille modeste sur de petites instances - tous deux dans les minimums recommandés, je crois. Dans les deux cas, RAM+swap=3G. Dans un cas, une instance Digital Ocean avec 1G de RAM et 2G de swap, dans l’autre cas, une instance Hetzner avec 2G de RAM et 1G de swap.

Voici trois instantanés du processus ember, sur la machine DO, en utilisant ps auxc

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 87.7 65.1 32930460 657936 ?     Rl   16:57   2:23 ember

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 84.9 60.7 43572204 612668 ?     Rl   16:57   2:57 ember

USER       PID %CPU %MEM      VSZ    RSS TTY   STAT START   TIME COMMAND
1000     10342 81.2 55.2 43405220 557128 ?     Rl   16:57   3:40 ember

Évidemment, la taille de processus de 43 Go n’est pas entièrement présente en mémoire virtuelle car nous n’avons que 3 Go disponibles. Utiliser 65 % de la taille de la RAM pour le RSS est impressionnant, mais pas en soi un problème. La quantité de mémoire libre et de swap libre montre que la machine est proche d’une condition de manque de mémoire (OOM), ce qui entraînerait très probablement la suppression d’un processus et une fin peu ordonnée de la mise à jour.

Voici free comme instantané à un moment donné :

# free
              total        used        free      shared  buff/cache   available
Mem:        1009140      863552       72768        6224       72820       34868
Swap:       2097144     1160628      936516

Pour essayer de capturer la situation au plus près de l’échec, j’ai utilisé vmstat 5

# vmstat 5 5
procs -----------memory----------    ---swap-- -----io----  -system-- ------cpu-----
 r  b   swpd    free   buff  cache    si    so    bi    bo   in    cs us sy id wa st
 3  0 1392140  61200  11632  76432    41    32   117    93    0     1  2  1 97  0  0
 1  1 1467220  63416    324  67284  8786 20499 13178 20567 2539  8924 77 13  0 10  0
 0  2 1593340  57916   1096  53832 24262 46868 29986 46889 5377 18534 44 22  0 34  0
 4  0 1155632 120680   2772  86280 39111 35424 54768 37824 6987 25174 38 27  0 35  0
 3  0 1102988  74096   2852  85276 11261   246 12610   271 1879  6365 86  6  0  8  0

Vous remarquerez beaucoup de commutations de contexte (cs), beaucoup d’activité disque (bi, bo) et beaucoup d’activité de swap (si, so), mais le plus important est l’utilisation du swap jusqu’à 1,6 Go avec la mémoire libre descendant à 60 Mo et seulement 54 Mo d’utilisation de buffer. Cela signifie qu’environ 2,6 Go des 3 Go de mémoire virtuelle disponibles sont utilisés. C’est 87 % de la capacité. (Cela pourrait être un peu pire, car nous échantillonnons seulement toutes les 5 secondes.)

Notez que la situation était préoccupante (environ 2 Go utilisés, donc pas aussi proche de la critique qu’aujourd’hui) lorsque j’ai mis à jour en août :

# vmstat 5 5
procs -----------memory----------    ---swap-- -----io----  -system-- ------cpu-----
 r  b    swpd   free   buff  cache    si    so    bi    bo   in    cs us sy id wa st
 3  0  700404  62740   1956  48748    35    29   108    92    3     8  2  1 96  0  1
 1  0  741000  65996   1880  44360  3708 11190  3982 11191  643  1437 92  4  0  3  1
 1  0  834836  70452   1480  53856   528 18969  4274 18974  532  1575 93  6  0  1  0
 4  1 1010144  82192   4644  44400 30065 38803 35455 39946 4432 19267 28 26  0 39  7
 1  0  644116 307764   1644  55348 24406 21154 27724 21945 2551  8672 52 22  0 21  6
4 « J'aime »

Salut @Ed_S - quelle version de Discourse utilisiez-vous pour ces tests ? Nous mettons régulièrement à jour ember-cli et ses extensions, je veux donc juste être sûr que nous examinons la même chose.

De plus, combien de cœurs de processeur vos machines virtuelles ont-elles ? 1 ? (vous pouvez vérifier en exécutant lscpu dans la console)

Pour que nous travaillions tous avec les mêmes données, pourriez-vous essayer d’exécuter :

/var/discourse/launcher enter app
cd /var/www/discourse/app/assets/javascripts/discourse
apt-get update && apt-get install time
NODE_OPTIONS='--max-old-space-size=2048' /usr/bin/time -v yarn ember build -prod

Sur mon droplet de test (1 CPU, 1 Go de RAM, 2 Go de swap), je vois ceci :

Command being timed: "yarn ember build -prod"
	User time (seconds): 369.74
	System time (seconds): 22.62
	Percent of CPU this job got: 81%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 8:02.73
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 774912
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 253770
	Minor (reclaiming a frame) page faults: 1158920
	Voluntary context switches: 519269
	Involuntary context switches: 383328
	Swaps: 0
	File system inputs: 7521784
	File system outputs: 316304
	Socket messages sent: 0
	Socket messages received: 0
	Signals delivered: 0
	Page size (bytes): 4096
	Exit status: 0

Nous utilisons ici des outils ember assez standard, donc je ne suis pas sûr qu’il y ait beaucoup de choses que nous puissions faire en termes de configuration pour réduire l’utilisation de la mémoire. Notre objectif à long terme est de passer à l’utilisation d’Embroider, ce qui pourrait nous donner plus d’options.

1 « J'aime »

Merci @david - j’apprécie qu’Ember soit une chose en soi.

Je viens de faire ces commandes.

# /var/discourse/launcher enter app
Architecture x86_64 détectée.

AVERTISSEMENT : Nous sommes sur le point de commencer à télécharger l'image de base de Discourse
Ce processus peut prendre de quelques minutes à une heure, en fonction de la vitesse de votre réseau

Veuillez patienter

2.0.20220720-0049 : Tirage de discourse/base
Digest : sha256:7ff397003c78b64c9131726756014710e2e67568fbc88daad846d2b368a02364
Statut : Nouvelle image téléchargée pour discourse/base:2.0.20220720-0049
docker.io/discourse/base:2.0.20220720-0049

Il s’agit d’une installation de production, donc, depuis hier, elle était à jour. Signalant actuellement :

Installé 2.9.0.beta12 (8f5936871c)

C’est une instance à un seul processeur, comme la vôtre, elle a 1 Go de RAM et 2 Go de swap.

Le résultat de la commande time était

Terminé en 303,21 s.

Commande chronométrée : « yarn ember build -prod »
Temps utilisateur (secondes) : 222,71
Temps système (secondes) : 17,17
Pourcentage du CPU obtenu par ce travail : 78 %
Temps écoulé (horloge murale) (h:mm:ss ou m:ss) : 5:04.15
Taille moyenne du texte partagé (kilo-octets) : 0
Taille moyenne des données non partagées (kilo-octets) : 0
Taille moyenne de la pile (kilo-octets) : 0
Taille totale moyenne (kilo-octets) : 0
Taille maximale du jeu résident (kilo-octets) : 702292
Taille moyenne du jeu résident (kilo-octets) : 0
Fautes de page majeures (nécessitant des E/S) : 348190
Fautes de page mineures (récupération d'une trame) : 1152689
Commutations de contexte volontaires : 617736
Commutations de contexte involontaires : 774189
Swaps : 0
Entrées du système de fichiers : 5001936
Sorties du système de fichiers : 318280
Messages de socket envoyés : 0
Messages de socket reçus : 0
Signaux délivrés : 0
Taille de la page (octets) : 4096
Statut de sortie : 0

Immédiatement avant, j’avais mis à jour l’hôte et redémarré, donc tout dans le conteneur aurait été fraîchement redémarré.

Le pire de l’utilisation de la mémoire tel que rapporté par un vmstat exécuté dans une autre fenêtre :

# vmstat 1
procs  -----------mémoire----------    ---swap--  -----io----   -système------cpu-----
 r  b    swpd   free   buff  cache    si     so    bi     bo    in    cs us sy id wa st
 2  0  704000 136044  24136 158144  1517   3503  8256   4377   886  3564 43  8 43  6  0
...
 5  0 1451436  71604   1248  50196 55016 110236 73204 121060 13152 45971 29 60  0 10  1
2 « J'aime »

Il semble que nous ayons explicitement augmenté la mémoire heap autorisée de Node de 500 Mo à 2 Go - peut-être est-ce un pas de trop, et 1,5 Go serait mieux :

Il convient de noter qu’Ember n’est pas la seule chose qui tourne sur la machine, et nous sommes à la limite globale de RAM+swap. L’historique de la machine et les besoins de tous les autres processus en cours entrent donc en jeu. Mon redémarrage a peut-être aidé à atteindre une marque de niveau supérieur plus basse par rapport à hier.

La pull request ci-dessus a été référencée dans
Échec de la mise à niveau de l’instance Discourse au 15 février 2022
où nous notons également que quelqu’un a eu une pénurie de mémoire qui a été résolue par un redémarrage.

Il est regrettable que la commande time ne signale pas l’utilisation maximale de la mémoire. Peut-être, sur une machine avec au moins 3 Go de RAM et pas de swap, le compteur RSS indiquerait l’utilisation maximale d’Ember. Ou peut-être pourrions-nous utiliser une autre tactique - plusieurs sont décrites ici et il y a quelques idées ici aussi.

Ce qui est gênant, c’est que nous nous intéressons vraiment à l’utilisation de la mémoire ici, alors que dans de nombreux cas, les gens s’intéressent à l’utilisation de la RAM, ce qui est une question différente.

3 « J'aime »

La raison pour laquelle nous avons ajouté ce drapeau est que le propre tueur OOM de Node tuait la construction - 500 Mo n’était pas suffisant. Je suis heureux d’essayer de le régler sur 1,5 Go - je viens de l’essayer sur ma gouttelette et cela semble fonctionner correctement. En fait, même 1,0 Go semble suffisant.

J’ai essayé de suivre l’utilisation de la mémoire avec différentes tailles de tas maximales :

(while(true); do (free -m -t | grep Total | awk '{print $3}') && sleep 0.5; done) | tee 1000mb.csv

Cela montre cette utilisation pendant la construction :

Il y avait très peu de différence dans le temps de construction, mais les limites de 1 Go et 1,5 Go produisent clairement moins d’utilisation globale. Comme prévu, la sortie time montre beaucoup moins de « fautes de page majeures » lorsque la limite de nœud est plus basse.

Il est curieux que la différence entre 1,5 Go et 1 Go soit si faible… :face_with_monocle:

Quoi qu’il en soit, je suis d’accord pour dire que la diminution de la limite est une bonne idée. Pour nous assurer que cela n’affecte pas les performances de construction sur des machines plus performantes, je pense que nous ne devrions dépasser la limite que lorsque nous savons qu’elle est trop basse. Sinon, nous pouvons laisser Node utiliser sa valeur par défaut.

Voici une PR - nous essaierons de la fusionner bientôt. Merci d’avoir soulevé ce point @Ed_S !

4 « J'aime »

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.