Question Mémoire en constante augmentation dans l'application Rails


J'ai récemment lancé une nouvelle application Ruby on Rails qui a bien fonctionné en mode développement. Après le lancement que j'ai connu, la mémoire utilisée augmente constamment:

Screen dump from New Relic, Dyno memory usage

UPDATED: When this screen dump from New Relic was taken. I have scheduled a web dyno restart every hour (one out of two web dynos). Thus, it does not reach the 500Mb-crash level and it actually gets a bit of a sig saw pattern. The problem is not at all resolved by this though, only some of the symptoms. As you can see the morning is not so busy but the afternoon is more busy.

ACTUALISÉ: Lorsque cette copie d'écran (celle ci-dessous) de New Relic a été prise. J'ai programmé un redémarrage web chaque heure (un web dyno sur deux). Ainsi, il n'atteint pas le niveau de crash de 500 Mo et il se caractérise par un léger effet de scie. Le problème n'est pas du tout résolu par cela, mais seulement certains des symptômes. Comme vous pouvez le voir, la matinée n'est pas très occupée mais l'après-midi est plus occupé. J'ai effectué un téléchargement à 11h30 pour un petit détail, cela n'aurait pas pu affecter le problème même s'il apparaît comme tel dans les statistiques.

On peut noter également que c'est la mémoire MIN qui continue d'augmenter même si le graphique montre la mémoire AVG. Même lorsque le graphique semble descendre temporairement dans le graphique, la mémoire minimale reste la même ou augmente. La mémoire MIN ne diminue jamais!

L'application (sans redémarrage du dyno) augmentera en mémoire jusqu'à ce qu'elle atteigne le niveau maximal chez Heroku et l'application se bloque avec l'exécution des types d'erreurs expirés.

Je ne suis pas un grand programmeur mais j'ai déjà fait quelques applications sans avoir ce type de problème.

Dépannage effectué

A. Je pensais que le problème se situerait dans le filtre before_filter dans le application_controller (Les variables du contrôleur d’application vont-elles provoquer une fuite de mémoire dans Rails?) mais ce n'était pas le problème.

B. J'ai installé oink mais cela ne donne aucun résultat (du tout). Il crée un fichier oink.log mais ne donne aucun résultat lorsque je lance "heroku run oink -m log / oink.log", quel que soit le seuil.

C. J'ai essayé bleak_house mais il était obsolète et ne pouvait pas être installé

D. J'ai googlé et lu la plupart des articles dans le sujet mais je ne suis pas le plus sage.

E. J'aimerais tester memprof mais je ne peux pas l'installer (j'ai Ruby 1.9x et je ne sais pas vraiment comment le rétrograder à 1.8x)

Mes questions:

Q1. Ce que j'aimerais vraiment savoir, c'est le nom de la ou des variables qui augmentent pour chaque demande, ou du moins quel contrôleur utilise le plus de mémoire.

Q2. Est-ce qu'un contrôleur comme le code ci-dessous augmentera en mémoire?

related_feed_categories = []
@gift.tags.each do |tag|
  tag.category_connections.each do |cc|
    related_feed_categories << cc.category_from_feed
  end
end

(désolé, SO ne reformatera pas le code pour être facilement lisible pour une raison quelconque).

Ai-je besoin de "tuer" related_feed_categories avec "related_feed_categories = nil" après ou est-ce que le garbage collector le gère?

Q3. Quelles seraient mes principales choses à rechercher? En ce moment, je ne peux pas le limiter à tout. Je ne sais pas quelle partie du code il faut approfondir et je ne sais pas vraiment quoi chercher.

Q4. Au cas où je ne peux vraiment pas résoudre le problème. Existe-t-il un service de conseil en ligne où je peux envoyer mon code et lui demander de trouver le problème?

Merci!

ACTUALISÉ. Après avoir reçu des commentaires, il pourrait s'agir de sessions. C'est une partie du code que je suppose pourrait être mauvaise:

# Create sessions for last generation
friend_data_arr = [@generator.age, @generator.price_low, @generator.price_high]
friend_positive_tags_arr = []
friend_negative_tags_arr = []
friend_positive_tags_arr << @positive_tags
friend_negative_tags_arr << @negative_tags    
session["last_generator"] = [friend_data_arr, friend_positive_tags_arr, friend_negative_tags_arr]

# Clean variables
friend_data_arr = nil
friend_positive_tags_arr = nil
friend_negative_tags_arr = nil

il est utilisé dans le générateur # show controller. Lorsque certains cadeaux ont été générés via mon moteur de génération de cadeaux, j'enregistre les entrées dans une session (au cas où ils souhaiteraient utiliser ces informations ultérieurement). Je ne tue ou n'expire jamais ces sessions, au cas où cela pourrait entraîner une augmentation de la mémoire.

Mis à jour à nouveau: J'ai supprimé ce morceau de code mais la mémoire augmente encore, donc je suppose que cette partie n'est pas la même, mais un code similaire peut causer l'erreur?


11
2017-09-25 07:41


origine


Réponses:


Il est peu probable que nos related_feed_categories provoquent cela.

Utilisez-vous beaucoup de fichiers?

Combien de temps conservez-vous les données des sessions? On dirait que vous avez un site de commerce électronique, conservez-vous des objets dans les sessions?

Fondamentalement, je pense que ce sont des fichiers, ou une session, ou une augmentation des données temporaires vidées lorsque le serveur plante (memcache?).

En pleine nuit, je suppose que nous avons moins de clients. Pouvez-vous poster le même graphique de mémoire, aux heures de pointe?

Cela peut être lié à ce problème: La mémoire grandit indéfiniment dans une application Rails vide

METTRE À JOUR :

Les rails ne stockent pas toutes les données du côté client. Je ne me souviens plus du magasin par défaut, sauf si vous choisissez le cookie :: store, les rails n'envoient que des données comme session_id.

Ce sont quelques lignes directrices sur les sessions, le ActiveRecord :: SessionStore semble être le meilleur choix à des fins de performances. Et vous ne devriez pas garder de gros objets ni de données secrètes dans les sessions. Plus sur la session ici: http://guides.rubyonrails.org/security.html#what-are-sessions

Dans la partie 2.9, vous avez une explication pour détruire les sessions, inutilisées pendant un certain temps.

Au lieu de stocker des objets dans des sessions, je vous suggère de stocker l'URL donnant les résultats de la recherche. Vous pouvez même le stocker dans une base de données, offrant la possibilité de sauvegarder quelques recherches à votre client, et / ou de charger par défaut le dernier utilisé.

Mais à ce stade, nous sommes toujours, pas tout à fait sûr que les sessions sont les coupables. Pour être sûr, vous pouvez essayer sur un serveur de test, de tester votre application avec des sessions qui arrivent à expiration. Donc, fondamentalement, vous créez un grand nombre de sessions, et peut-être 20 minutes plus tard, les rails doivent les supprimer. Si vous constatez une différence dans la consommation de mémoire, cela réduira les choses.

Premier cas: la mémoire baisse de manière significative à l'expiration des sessions, vous savez que c'est lié à la session.

Deuxième cas: la mémoire augmente plus rapidement, mais n'abandonnez pas à l'expiration des sessions, vous savez qu'elle est liée à l'utilisateur, mais pas à la session.

Troisième cas: rien ne change (augmentation de la mémoire habituelle), vous savez donc que cela ne dépend pas du nombre d'utilisateurs. Mais je ne sais pas ce qui pourrait causer ça.

Lorsque je parle de stress tests, je veux dire un nombre important de séances, pas vraiment un test de résistance. Le nombre de sessions dont vous avez besoin dépend de votre nombre moyen d'utilisateurs. Si vous aviez 50 utilisateurs, avant que votre application ne tombe en panne, 20 à 30 sessions pourraient être importantes. Donc, si vous les aviez à la main, configurez un délai d'expiration plus élevé. Nous cherchons simplement des différences dans la gestion de la mémoire.

Mise à jour 2:

C'est probablement une fuite de mémoire. Donc, utilisez un espace objet, il a une méthode count_objects, qui affichera tous les objets actuellement utilisés. Cela devrait restreindre les choses. Utilisez-le lorsque la mémoire a déjà beaucoup augmenté.

Sinon, vous avez bleak_house, un joyau capable de détecter les fuites de mémoire, mais les outils ruby ​​pour les fuites de mémoire ne sont pas aussi efficaces que les java, mais ça vaut le coup d'essayer.

Github: https://github.com/evan/bleak_house

Mise à jour 3 :

Cela peut être une explication, ce n'est pas vraiment une fuite de mémoire, mais cela augmente la mémoire: http://www.tricksonrails.com/2010/06/avoid-memory-leaks-in-ruby-rails-code-and-protect-against-denial-of-service/

En bref, les symboles sont conservés en mémoire jusqu'à votre redémarrage ruby. Ainsi, si les symboles sont créés avec un nom aléatoire, la mémoire augmentera jusqu'à ce que votre application plante. Cela ne se produit pas avec les cordes, les sont GCed.

Bit old, mais valide pour ruby ​​1.9.x Essayez ceci: Symbol.all_symbols.size

Mise à jour 4:

Donc, vos symboles sont probablement la fuite de mémoire. Maintenant, nous devons encore trouver où cela se produit. Utilisez Symbol.all_symbols. Il vous donne la liste. Je suppose que vous pouvez stocker ceci quelque part, et faire un diff avec le nouveau tableau, afin de voir ce qui a été ajouté.

Cela peut être i18n ou quelque chose d'autre générant de manière implicite comme i18n. Mais de toute façon, cela génère probablement des symboles avec des données aléatoires dans le nom. Et puis ces symboles ne sont plus jamais utilisés.


5
2017-09-27 14:13



En supposant category_from_feed renvoie une chaîne (ou un symbole peut-être), une augmentation de 300 Mo est tout à fait improbable. Vous pouvez y arriver en profilant ceci:

4_000_000.times {related_feed_categories << "Loooooooooooooong string" }

Cet extrait de code utilisait environ 110 Mo d’utilisation de la mémoire.

Je regarderais les connexions à la base de données ou les méthodes qui lisent un fichier et ne le ferment pas ensuite. Je peux voir que cela est lié aux flux, ce qui signifie probablement que vous utiliserez XML. Cela peut être un point de départ aussi.


Afficher ceci comme réponse parce que cela a l'air mauvais dans les commentaires: /


1
2017-09-27 13:44