Forum Linux.général Erreur "Cannot allocate memory" généralisée

Posté par  .
Étiquettes : aucune
0
17
fév.
2011
Bonjour,

je rencontre actuellement un gros soucis avec un de mes serveurs web/postgresql.
Lorsque je lui envoie du trafic (scripts PHP + quelques images), au bout d'un certain temps tous les process PHP meurt à cause d'une erreur "Out of memory". Au même moment, Postgresql log des erreurs "Cannot allocate memory". Et encore au même moment, exim4 log aussi une erreur "Cannot allocate memory" dans le paniclog...

Le plus étrange c'est que via htop je surveille l'utilisation de la mémoire, et il en utilise à peine 4Go sur les 32 dispo, et même en comptant le cache il en reste la moitié de libre. Je précise aussi que Postgresql a 6Go d'alloué, les process PHP ont une limite de 512Mo. D'ailleurs, dans l'erreur le process PHP disait avoir alloué 512Ko, c'est à n'y rien comprendre.

J'ai cherché longuement mais je ne trouve rien de semblable, et depuis que ce matin j'ai vu ce message dans le paniclog de exim4 c'est encore pire, j'avoue que ça me dépasse.

Si quelqu'un a un début d'idée ça m'aiderait beaucoup !
Merci.
  • # Question bête…

    Posté par  . Évalué à 6.

    … ton système est en 32 ou en 64 bits ?
    • [^] # Re: Question bête…

      Posté par  . Évalué à 4.

      je plussoie la question de "hydraze"
      • [^] # Re: Question bête…

        Posté par  . Évalué à 2.

        oui et non,
        si le système est installé en 32bits et qu'il reconnait bien les 32Go de ram, c'est que le PAE est bien activé,
        la limite des 4Go s'appliquera toujours mais pour chaque processus indépendamment !,
        Que te renvoie un simple "free" par exemple ?
        • [^] # Re: Question bête…

          Posté par  . Évalué à 2.

          il me semblait que 32bits + PAE ca permettait à l'OS d'allouer la memoire au dela de 4Go
          mais que la limite par processus etait toujours de 2Go.

          bon ca n'explique pas que PHP plante avec une limite posée à 512Mo
          • [^] # Re: Question bête…

            Posté par  . Évalué à 1.

            Sur 32-bit, avec HIGHMEM ou non, la mémoire virtuelle par processus est limitée à 3B. Le dernier GB (à partir de l'adresse 0xc0000000) est mappé par le noyau, pour éviter de devoir flusher le TLB à chaque changement de contexte user mode/kernel mode.
            Il existe un patch 2G/2G qui permet au noyau d'utiliser jusqu'à 2G de RAM sans HIGHMEM, mais n'est pas couramment utilisé.
            Il exist(ait ?) aussi un split 4G/4G qui permettait d'utiliser jusqu'à 4G de mémoire, mais donc au prix d'un flush TLB à chaque changement de contexte.
    • [^] # Re: Question bête…

      Posté par  . Évalué à 1.

      Le système est bien en 64 bits.

      A noter que tant que j'ai pas de trafic sur apache, postgresql n'a aucun problème.
      J'ai essayé de changer les paramètres de ulimit (comme le max locked memory) en mettant les paramètres de mon ancien serveur qui fonctionne, ça n'a rien changé.

      A noter aussi que là j'utilise apache avec le MPM prefork, et qu'avant hier quand j'utilisais le MPM event avec PHP en CGI je n'avais pas ces problèmes.
      • [^] # NUMA? kernel leak? userland leak? mm bug?

        Posté par  (site web personnel) . Évalué à 1.

        On peut avoir une copie du message d'OOM complet ? Il te dit exactement ce qui tombe à court de mémoire normalement mais sans ça c'est un peu dur de diagnostiquer.

        pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

  • # Suite

    Posté par  . Évalué à 1.

    Bon, on a baissé le KeepAliveTimeout de 15 à 2s et ça a l'air de fonctionner. On va peut-être essayer sans KeepAlive vu que la machine peut tenir la charge. M'enfin ça n'explique pas pourquoi avec le KeepAlive on a ces problèmes.
    • [^] # Re: Suite

      Posté par  . Évalué à 2.

      keepalive garde les connexions actives meme sans activité (pendant le delai demandé).

      ton prefork ouvre des processes en attente de connexion potentielle.

      => apache va ouvrir
      5 prefork (il me semble par defaut) et va tacher d'en avoir toujours 5 d'avances.
      si tu as 1000 clients, il va donc tacher d'ouvrir 1005 process.

      => avec un keepalive à 15sec, chaque client qui se connecte ne serait-ce qu'une fois, laisse le process en attente pour 15sec meme s'il ne se passe rien

      il faut surtout essayer de voire ce qui se passe quand ca plante, par exemple ce que dit un
      ps fax | grep apache quand ca "plante"
    • [^] # Re: Suite

      Posté par  . Évalué à 2.

      Tu as probablement un paramètre MaxClients trop élevé.
      Par défaut, il est à 150. C'est très bien pour des process apache légers. Par contre, avec des process lourds c'est excessif.

      Dans ton cas, avec 512 Mo/process (limite PHP), tu risques d'avoir besoin de 150*0.5Go = 75 Go de RAM.

      Le fait que la réduction du KeepAliveTimeout résolve le problème semble confirmer l'hypothèse : avec un KeepAliveTimeout plus faible, il y a moins de process Apache.

      Par ailleurs, tu as intérêt à avoir un MaxRequestsPerChild non nul pour que les process Apache puissent rendre périodiquement la mémoire allouée.
      • [^] # Re: Suite

        Posté par  . Évalué à 1.

        J'aurai approuvé, seulement lors de ces problèmes je ne voyais AUCUNE augmentation de la consommation mémoire via htop. Alors à moins que htop / top / free mentent, je doute que j'ai réellement utilisé trop de mémoire.

        De plus le 512Mo par process PHP est une limite, pas une valeur toujours atteinte; on a aucun script qui va consommer jusqu'à 512Mo de mémoire.

        Concernant le MaxRequestsPerChild on est à 10000.
        • [^] # Re: Suite

          Posté par  . Évalué à 1.

          J'aurai approuvé, seulement lors de ces problèmes je ne voyais AUCUNE augmentation de la consommation mémoire via htop. Alors à moins que htop / top / free mentent, je doute que j'ai réellement utilisé trop de mémoire.

          Pourtant, d'après tes dires, la seule modification a été le passage d'Apache MPM event à MPM prefork. Autrement dit, d'un Apache léger un utilisation mémoire à un Apache "lourd".
          Avec 32 Go de RAM - les 6 Go de Postgres, pas besoin d'atteindre les 512 Mo par process Apache pour exploser la RAM si 150 process sont démarrés.
          • [^] # Re: Suite

            Posté par  . Évalué à 1.

            Effectivement, mais comme dit je vérifiais la consommation de mémoire via htop, vmstat, dstat au moment même où ça plantait. La valeur "used" ne bougeait pas ou très peu. Si ça avait été ça le problème, ça aurait été simple :)
            De plus, on atteint sans problème 3000 process Apache avec cette configuration, la plupart consomment quasiment rien en mémoire (et notre script php le plus appelé travaille sur peu de données, de l'ordre de quelques Ko).

            Mais grâce à l'explication de neologix plus bas, j'ai cherché les effets sur Apache du passage de la variable vm.overcommit_memory à 2. Et d'après un post sur serverfault.com, ça ne fait pas bon ménage.
            Bon j'ai pas pu tester en revenant sur un KeepAliveTimeout à 15, mais rien que là en observant le fichier /proc/meminfo j'ai vu que la valeur de Committed_AS a tendance à dépasser CommitLimit.
            Si j'ai bien compris ce que j'ai lu, en passant overcommit_memory à 2 ça serait impossible, ce qui expliquerait les problèmes d'allocation mémoire commun à Postgresql, Apache, PHP et exim. Ça me parait le plus probable.

            En tout cas cette histoire m'apprendra à faire de la pré-optimisation...
  • # attention à l'overcommitting

    Posté par  . Évalué à 2.

    Que renvoie "sysctl -a | grep overcommit" ?
    Que renvoie un "cat /proc/meminfo" (particulièrement la ligne committed_AS) ?
    • [^] # Re: attention à l'overcommitting

      Posté par  . Évalué à 1.

      sysctl -a:
      vm.overcommit_memory = 2
      vm.overcommit_ratio = 100


      Ce n'est pas les paramètres par défaut, j'avais appliqué ces changements en me basant sur les recommandations du livre "Postgresql 9.0 High Performance".

      /proc/meminfo:
      Committed_AS: 18687308 kB

      Ça fait 17Go, mais que représente cette ligne ?
      • [^] # Re: attention à l'overcommitting

        Posté par  . Évalué à 2.

        vm.overcommit_memory = 2
        vm.overcommit_ratio = 100

        Ce n'est pas les paramètres par défaut, j'avais appliqué ces changements en me basant sur les recommandations du livre "Postgresql 9.0 High Performance".


        Cela désactive l'overcommiting, cela signifie que le noyau n'allouera pas plus de SWAP + 100% RAM = SWAP + RAM. Sans cela, malloc peut renvoyer une adresse valide (i.e. pas NULL), mais l'OOM-killer se mettra en branle au moment où elle touchera les pages.

        /proc/meminfo:
        Committed_AS: 18687308 kB

        Ça fait 17Go, mais que représente cette ligne ?



        La mémoire réellement allouée. Le problème c'est que la valeur reportée par free (même en prenant en compte buffer/cache) est à peu près aussi fiable que madame Soleil : par exemple, sur certains noyaux, avec un FS ext3 monté avec data=ordered, si tu supprimes un fichier alors qu'il est ouvert, le taille reportée du page cache diminue, mais pas la mémoire free.
        Un autre problème, c'est que tant que la page n'a pas été touchée par l'application, elle ne sera pas reportée comme utilisée.
        Committed_AS est la quantité de mémoire qui a été réellement allouée par le noyau.
        Il serait bien de faire un "watch cat /proc/meminfo" pendant que tu es en charge...
        • [^] # Re: attention à l'overcommitting

          Posté par  . Évalué à 1.

          Si je comprends bien, actuellement 17Go sont alloués mais seulement 4 utilisés. J'ai jamais monitoré cette valeur, tout les outils que j'ai utilisé (vmstat, dstat, htop, top) n'affichent que le used/cache.

          J'ai bien envie de tester en monitorant meminfo pour en avoir le coeur net mais comme c'est une machine de prod et qu'on a contourné le problème je pense pas que mon chef sera d'accord.

          En tout cas merci pour les explications.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.