août 28

Et les développeurs découvrirent la CRON…

Avec Magento et d’autres frameworks, il devient possible de faire exécuter au site une commande à heure/date/jour fixe par le mécanisme de Cron table. Ce mécanisme, très vieux (au moins 25 ans) et très stable est connu de tous les administrateurs systèmes et réseau, ses excès et débordements occasionnels (si l’on ne fait pas attention au contenu) aussi.

Sauf que quand les développeurs ont mis la mains sur ce petit outil d’automatisation, une nouvelle frontière s’est ouverte en terme de possibilité. Application d’un traitement sur tout le catalogue de nuit, système de calcul des réapprovisionnements, gestions de commandes ou des réductions etc…

Well, le principe est bon alors le partager doit être bon quelque part ?

Mais cela fait maintenant un moment qu’avec l’apparition de PHP, cette question revient :

« Vous pourriez passer la memory limit à 1, 2, 4 Go ? »
Non.

« Mais j’en ai besoin pour mes traitements »
Non.

« Non quoi ? »
Non je ne passerai pas la memory limit à 1,5 Go car vous n’en avez pas besoin.

Pourquoi ?

Déjà parce que l’on a pas besoin de 1 ou 2 ou 4 Go pour effectuer un traitement, aussi volumineux soit-il. Il est *presque* toujours possible de fragmenter le traitement en sous lots plus petits, d’allouer et désallouer sa RAM plus subtilement et d’une manière générale privilégier une méthode de travail moins RAM intensive. (écriture et stockage de résultats partiels, tableaux indexés, traitement par plus petit lots, utilisation de la gestion de mémoire du Zend framework etc…)

Que personne ne tente de s’abriter derrière le *presque*, le nombre des algorithmes complexes non factorisables ou fractionnables est connu et, dans leur très grande majorité, ils touchent aux traitements mathématiques, à la cryptographie ou aux problèmes dits « NP-complets ». Donc NON, il n’est pas impossible de programmer différemment un traitement PHP sur une collection de données, fussent elle grande.

D’ailleurs, la preuve, au final, le développeur contourne le problème et arrive à utiliser une memory limit raisonnable tout en résolvant son problème.

Et pourtant, elle tournait !

Ensuite 1 Go de RAM, c’est beaucoup. Au sens propre.

C’est à dire qu’à une époque pas si lointaine, on chargeait et traitait des collection de données 2 fois moins grandes mais également avec 10 fois moins de RAM. Le catalogue d’une société il y a 10 ans était peut être deux fois moins gros mais peut importe le système utilisé à l’époque, ca tournait et la RAM, à l’époque, il y en avait 10 fois moins et pourtant, ca tournait.

Le coté orgiaque de la progression du matériel et de ses coûts fausse le sens des réalités. Oui un cycle processeur ca compte. Oui une boucle mal optimisée ca joue, surtout multipliée par des milliers de visites. Oui 1 Go de RAM ce n’est pas rien. Selon la configuration de la machine, cela peut même représenter le quart de ses ressources mémoire…

De plus, la memory limit est posée pour tous les processus PHP, pas pour un en particulier. Résultat il est possible qu’un seul script soit gourmand mais rien ne nous certifie que cela ne sera pas le cas d’un autre. Et si 5 ou 6 processus PHP se mettent à consommer 1 Go de RAM, on arrive vite à des sommes qui peuvent mettre des serveurs à mal.

A une époque pas si lointaine sur Amiga et Atari ST, on optimisait jusqu’au moindre octet maintenant c’est une culture perdue, qu’on considère comme dépassée mais sincèrement, cet esprit était le bon. La société de l’hyper consommation nous pousse à manger plus, dépenser plus, imprimer plus et allouer plus de RAM. Ça va avec, le gâchis est devenu une culture. Pourquoi écrire 10 lignes de plus pour avoir une gestion plus rationnelle alors que comme cela ca marche ?

Sans compter que bon nombre de script n’exit jamais et reste en mémoire sans savoir quoi faire, à part bloquer 1 Go de RAM, pour rien.

Quelques bribes de solutions :

Fragmenter le traitement est le plus important, soit dans l’algorithme de traitement, soit dans la gestion de la mémoire.

Quand vous lisez un bouquin, vous le faite page après page et pas les 500 d’un coup, envisageons la même chose pour un serveur.

  1. Prenez la taille de votre traitement, diviser le par 64 ou 128 Mo et vous saurez le nombre de blocs à traiter, le nombre de processus qui devront s’exécuter à la suite pour venir à bout de la tâche. Une fois les résultats calculés, assemblez les au besoins.
  2. Traitez des tableaux ou des indexes qui référencent les données plutôt que toute la donnée en elle même, quand cela est possible.
  3. Utilisez des algorithmes et des clefs de hash pour sotcker et retrouver vos données.
  4. Traitez les données avec le langage le plus adapté. N’oubliez pas que PHP est 10 fois plus lent (au bas mot) que le C pour venir à bout d’un traitement. Sa gestion de la RAM est également moins efficace.
  5. Quand cela est possible, préférez un script SQL à un PHP qui fait du SQL, ca sera considérablement plus rapide et économe en ressources.
  6. Si vous continuer à faire vos Cron en PHP, utilisez Zend_Memory :
    Le composant Zend_Memory est destiné à gérer des données dans un environnement où la mémoire est limitée.
    Les objets mémoire (conteneurs de mémoire) sont produits par le manager de mémoire sur demande et mis en cache/chargés d’une manière transparente quand c’est nécessaire.

    (tiré de la doc ici : http://framework.zend.com/manual/fr/zend.memory.overview.html)
    ah… voila une solution élégante. J’utilise et si je dépasse la RAM allouer, ca swap sur le disque mes résultats intermédiaire.
    (Merci à Samuel Verdier de m’avoir soufflé la solution, il interviendra peut être prochainement sur ce blog pour nous donner des exemples concrets).

écrit par Philippe Humeau \\ tags: , , ,


7 commentaires sur “Non, je ne passerai pas la memory limit php à 1,5 Go !”

  1. 1. loopion Dit :

    Tres bon article mais j’attends tout de memes les exemples concret (genre en C je vois pas trop trop comment proceder…)
    La partie SQL ne s’applique malheureusement pas a tous les cas non plus.
    Par contre super interessant Zend_Memory!

  2. 2. Philippe Humeau Dit :

    ah ca je verrai bien un codeur venir témoigner en guest sur le blog sur comment on peut faire bien et propre ! des volontaires ?

  3. 3. DarkSmith Dit :

    Finalement ce qu’il manque a PHP c’est un mécanisme asynchrone pour les tache lourde qu’il est aberrant d’exécuter en même temps que le rendu de la page de l’utilisateur.
    Pour le moment une façon de faire c’est d’avoir un système de work queue (rabbitMQ ou encore Beanstalk). L’idée c’est d’enregistrer des taches très simple qui seront exécutées toutes les 1 à 2 minutes. De ce faite on obtient une application réactive et une queue en bg qui tourne a son rythme sans bouffer toute la RAM.

  4. 4. Philippe Humeau Dit :

    Gearman, MQseries sont aussi dans cette idée.

    J’aimerai bien qu’on ait un accès plus « sain » à la base de donnée, soit du sql en directe soit peut être un langage plus « système », enfin plus adapté à des traitements lourds. Effectivement le faire par petits lots au fil de l’eau est également très efficace.

  5. 5. Nom (required) Dit :

    Nous avons utilisé sur un projet récent ZendX_Console_Process_Unix, ça marche pas mal et nous avons gagné au moins deux choses:
    – traitement en asynchrone, donc des requêtes plus lejers à traiter
    – contrôle sur le séquençage de traitement, en choisissant un sous-ensemble distinct des données par worker

    Aussi tout le code de bootstrap et de chargement en mémoire et exécuté une seule fois.

  6. 6. Philippe Humeau Dit :

    CA c’est un très bon début de solution, on a un article à écrire à 6 mains là :) Ca vous dit ?

  7. 7. Slide Dit :

    DarkSmith, en fait, ce qu’il manque plutôt aux développeurs PHP c’est la possibilité de prendre du recul et de se dire « Tiens, quels résultats faudrait-il mieux que je précalcule en batch pour les faire faire dans la forme la plus adaptée, et placer ce résultat dans une table de précalcul ad-hoc » ? Je sais, je paraphrase le point 4…

Poster une réponse