XHTML.net

Technology talks by Loïc d’Anterroches

News, articles, PHP, scripts, XHTML/CSS, …

  1. Home
  2. PHP: Hypertext Preprocessor

PHP Tour 2011, j'y étais

The 2011-11-28 at 12:54 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.


et cela fut pour moi une très bonne conférence — chapeau bas à l’organisation par l’AFUP, des amateurs au sens noble du terme, aimant ce qu’ils font, ayant plaisir à partager, bravo. C’était la première fois que le contenu de ma présentation était non scientifique. J’ai quand même suivi le plan d’une présentation scientifique traditionnelle, en partant de mon problème et les moyens utilisés pour le résoudre. Pour les moyens, Mongrel2 et ZeroMQ, je pense que cela a fait tilt pour beaucoup. Chez certains, ce fut direct. Je vais donc avoir le plaisir de travailler avec l’université de Picardie pour des problèmes d’interface entre du super calculateur (400 CPU en mémoire partagée) et le web, en gros, ce que je suis en train de faire avec Cheméo.

Au niveau humain — et c’est ce qui m’intéresse souvent le plus dans les conférences — j’ai pu enfin mettre des visages sur des nicks et voir ainsi pour la première fois des gens avec qui j’ai échangé depuis des années. Rien que pour cela, cela valait la peine de faire le déplacement.

Je ferai un petit rapport avec ce que j’ai vu, ce que j’ai aimé, moins aimé et bien entendu je mettrai ma présentation en ligne (juste le temps d’ajouter des notes car sinon, cela risque d’être incompréhensible pour la majorité des gens).

Migration vers le PHP Tour 2011

The 2011-11-13 at 17:36 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

Le PHP Tour 2011 arrive bientôt, ne l’oubliez pas ! Pour moi, mon trajet sera dans le sens de la migration des grues cendrées probablement l’inverse pour la majorité des français, dans tous les cas, les sessions vont être passionnantes et montrent bien la qualité des acteurs en France, venez nombreux !

Migration des grues cendrées

J’ai eu la chance de croiser ce samedi environ 1000 grues cendrées (que je persiste à nommer des oies cendrées) au détour d’une promenade sur le haut d’un terril.

Photon me fait changer la manière de penser mes applications web

The 2010-12-18 at 16:50 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

Photon est un framework très très léger, mais surtout, c’est un framework qui a comme prérequis, l’utilisation de ZeroMQ. ZeroMQ est un moyen extraordinairement simple, de mettre en place une architecture en services. De petits services, simples et élégants, qui font une chose et bien. C’est la philosophie Unix appliquée aux services d’une application web.

Dans un retour d’expérience dans l’utilisation d’AWS, Netflix annonce avoir codé un "Singe Chaotique":

The Chaos Monkey’s job is to randomly kill instances and services within our architecture.

Photon permet de penser "services" et non plus application web. Par exemple, avec Pluf, Django, Symfony ou Rails, le principe est d’avoir un gros projet avec dedans une série de petites applications pour pouvoir maintenir le code facilement. Mais, si vous devez assurer la robustesse en cas de non disponibilité d’une part de votre application, vous ne pouvez que rarement. Ainsi, dans la majorité des cas, vous avez du code genre :

$user = get_my_user($request);
$options = $user->getOptions();
$products = $user->getRecommendations();

La fonction getOptions fonctionne tout comme getRecommendations dans le même processus/threads que le code général. Surtout, il est très difficile de pousser par exemple getRecommendations en dehors (via une API et des services) car la logique de développement avec ces frameworks et de tout avoir dans un gros projet.

Le futur est distribué et souple, les processus sont tués et rechargés en continu.

Un très joli projet qui vient d’être libéré est Pluton de Yahoo. C’est un projet permettant d’écrire du code genre :

$user = get_my_user($request);
$client = new PlutonClient();
$reqs = array('service.options', 'service.recommendations');
foreach ($reqs as $req) {
    $client->addRequest($req, $user);
}
$responses = $client->getAll(50); // timeout de 50 ms.
// Les get suivants sont rapides car en fait, l'info est déjà 
// disponible.
$options = $responses->get('service.options');
$products = $responses->get('service.recommendations');

Note : C’est du pseudo code, mais l’API suit cette logique.

Le côté intéressant est que le getAll lance les requêtes en parallèle. Surtout, si un service n’est pas là ou prend trop de temps pour répondre, $options ou $products seront par exemple mis à null et on pourra avoir une réponse dégradée, mais une réponse à l’utilisateur.

Cela implique de penser l’application comme une collections de composants qui acceptent les erreurs.

Ma grande question est maintenant de permettre d’introduire la logique du singe chaotique, de l’acceptation des erreurs, de manière élégante dans un projet utilisant Photon. Comment permettre de coder facilement une application web utilisant de multiples services avec chaque service pouvant ne pas répondre ?

Photon, le nouveau framework PHP qui va vite

The 2010-11-11 at 10:31 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

Photon, car rien ne va plus vite qu’un photon, tout simplement. Le projet Photon, en développement fermé pour le moment, est un framework PHP haute performance qui vient s’intégrer dans un projet très prometteur : Mongrel2.

Mongrel2 est un serveur web très récent, absolument pas mature (on ne peut pas faire de requêtes POST de plus de 200 ko avec), mais en même temps, répondant parfaitement à la demande des applications web à venir. Mongrel2 se base sur ZeroMQ pour transmettre une requête au serveur d’application et récupère la réponse de la même façon via ZeroMQ. ZeroMQ est une bibliothèque permettant la communication via des sockets entre différents composants. Sans serveur centralisé, extrêmement rapide, supportant de nombreux langages et des topologies de mise en production multiples, ZeroMQ est l’HTTP des backends, un système merveilleux pour connecter entre eux des éléments variés.

Pourquoi un nouveau framework quand Symfony2 ou Zend2 pointent le bout de leur nez ?

  • Les nouveaux frameworks PHP restent dans la logique PHP d’une requête qui est oubliée après son exécution. Photon dispose d’un serveur d’application pour répondre aux requêtes., comme Python, Ruby ou Java. C’est un ou plusieurs daemon qui tournent en continu.
  • Ces frameworks sont trop lents. Symfony2 sort 1800 req/s sur une énorme configuration, Photon sort 1800 req/s sur une toute petite configuration (voir plus bas).
  • Mongrel2 via ZeroMQ permet d’augmenter la puissance de votre backend sans reconfiguration de votre serveur. Par exemple, vous avez une application web qui fonctionne avec 4 daemons derrière, la charge augmente, vous pouvez en lancer 4 autres sans aucune reconfiguration, juste $ php photon.php start myproject, si la charge augmente encore plus, vous pouvez démarrer un autre serveur, mettre votre code dessus, taper $ php photon start myproject et vous augmentez la capacité de traitement de votre système. Aucune reconfiguration nécessaire, tout se fait automatiquement de manière transparente.
  • Vous pouvez aussi lancer 4 démons avec la version 1 de votre site et 1 avec la version 2 et vous assurer que seule une partie des visiteurs avec un cookie particulier accèdent à la version 2.
  • Vous pouvez bien entendu diminuer le nombre de vos serveurs à la volée si la charge diminue.
  • Vous profitez d’un daemon PHP, c’est à dire que vous pouvez facilement tenir une connexion permanente à votre base de données, à votre serveur d’application métier en Python.
  • Vous pouvez générer une réponse et l’envoyer à 128 clients d’un coup, idéal pour une application de chat…

Photon est un autre concept, Photon va vite, très vite même encore non optimisé, Photon utilise le meilleur de ce qui se fait pour PHP en ce moment.

Pour ce qui est de la maturité de Mongrel2, je discute chaque jour avec Zed, le créateur de ce serveur pour l’améliorer et m’assurer la parfaite interopérabilité avec Photon.

Performance de Photon sur le traditionnel "Hello World".

$ httperf --hog --server localhost --port 6767 --uri /handlertest/foo \
 --num-conn 5000 --num-call 10 --rate 180 --timeout 5
httperf --hog --timeout=5 --client=0/1 --server=localhost --port=6767 \
 --uri=/handlertest/foo --rate=180 --send-buffer=4096 --recv-buffer=16384 
 --num-conns=5000 --num-calls=10
httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE
Maximum connect burst length: 1

Total: connections 5000 requests 50000 replies 50000 test-duration 27.779 s

Connection rate: 180.0 conn/s (5.6 ms/conn, <=26 concurrent connections)
Connection time [ms]: min 4.6 avg 10.4 max 139.5 median 6.5 stddev 16.9
Connection time [ms]: connect 0.0
Connection length [replies/conn]: 10.000

Request rate: 1799.9 req/s (0.6 ms/req)
Request size [B]: 77.0

Reply rate [replies/s]: min 1799.1 avg 1799.9 max 1800.9 stddev 0.7 (5 samples)
Reply time [ms]: response 1.0 transfer 0.0
Reply size [B]: header 129.0 content 13.0 footer 0.0 (total 142.0)
Reply status: 1xx=0 2xx=50000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 2.18 system 22.68 (user 7.9% system 81.6% total 89.5%)
Net I/O: 384.9 KB/s (3.2*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

Le choix d’un num-call à 10 pour un rate à 180 est pour avoir un "Request rate" de 1800 req/s et donc égaler le "record" de Symfony2. Tout fonctionne sur la même machine, Mongrel2 est compilé en mode DEBUG donc avec le log de tout ce qui se passe. Maintenant, une petite comparaison des machines:

SpecMa petite machineTest Symfony2
RAM 2GB 7GB
CPU AMD Athlon 4850e (dual core, low power fanless )20 EC2 compute units (20 x 1.0/1.2 GHz sur 8 cores)

Ils ne donnent pas non plus la valeur intéressante, c’est à dire le Reply time. Avec n’importe quel système vous pouvez faire une moyenne de 10000 req/s, même avec un temps de réponse de 1 sec par requête. Il suffit de mettre plus de connexions en parallèle. Vous voyez ici, que pour Photon, la réponse est de 1ms par requête. Photon a donc besoin de 1ms pour apporter une requête au code métier et la renvoyer, vous pouvez donc faire ensuite des applications web ultra réactives. Et c’est là la chose importante et c’est pour cela que je développe Photon.

Mais bien entendu, le langage est le même, mais le concept est différent, Photon, c’est un serveur d’application en PHP, cela ne fonctionne donc pas avec de l’hébergement mutualisé et il faut savoir ce qu’on fait, mais si on sait, les performances sont extraordinaires, je sors en pointe juste 50% moins de requêtes que du statique… comparez votre framework avec un index.html contenant "Hello World!" et postez vos résultats ici… :-)

Avancée dans le projet PHP qui va vite

The 2010-10-11 at 10:47 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

Je continue de travailler sur le petit projet en PHP qui va vite. Sur un vieux laptop Core Duo d’il y a 3 ans, je sors plus de 1000 requêtes par seconde. Oui, c’est du PHP, oui c’est pour des pages dynamiques (un simple compteur pour le moment, qui s’incrémente à chaque requête). Ce n’est pas optimisé et ce n’est pas complet, je pense donc que le final devrait tourner autour de 500 requêtes par seconde. Dans tous les cas, cela dépote et ouvre nettement plus de possibilités que je ne pensais.

Transactions:		        7967 hits 
Availability:		      100.00 %
Elapsed time:		        6.83 secs
Data transferred:	        3.14 MB
Response time:		        0.00 secs
Transaction rate:	     1166.47 trans/sec
Throughput:		        0.46 MB/sec
Concurrency:		        0.95
Successful transactions:        7967
Failed transactions:	           0
Longest transaction:	        0.02
Shortest transaction:	        0.00

C’est donc un benchmark qui ne veut rien dire, juste que cela va plus vite que ce que je pensais, donc je suis content.

Mise à jour: En comparaison avec du statique, j’ai 2287.64 trans/sec sur un fichier texte… cela dépote…

Impact d'un namespace PHP sur la résolution d'une fonction globale

The 2010-10-06 at 09:06 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

Je prépare avec quelques excellents développeurs un projet vraiment innovant en PHP. Tellement innovant qu’il va probablement pousser à la retraite anticipée beaucoup de mes développements précédents et c’est bien ainsi.

Pour ce projet, je pense utiliser les espaces de noms (namespaces) PHP. La syntaxe avec le backslash est hideuse, mais elle a le mérite de permettre une meilleure réutilisation du code et ceci est important.

Par contre, le nouveau "niveau" introduit par les namespaces implique une étape de résolution supplémentaire quand on accède une fonction dans le code. En gros la question est : "Cette fonction est-elle dans l’espace courant ou non ? Si non, est-elle dans l’espace global ?"

Quel est le coût en performance de cette question ? Pour répondre, rien de tel qu’un test de 100 fois 1 000 000 de résolutions en forçant la résolution directement ou en laissant la question se faire poser. Les temps dans le tableau suivant sont pour 1 000 000 de résolutions, les min/max/moyenne et déviation sont sur les 100 tests.

MéthodeMoyenne (s)Min (s)Max (s)Std Déviation
Direct 0.95236 0.940090.968090.00506
Fallback0.99073 0.980331.009820.00472

La différence est donc inférieure à 4%. Ce n’est donc pas significatif à l’échelle d’une requête web. Pour gagner 1 ms sur le chargement d’une page en forçant l’appel direct, il faudrait avoir dans le rendu d’une page 26000 d’appels optimisables. On arrive vite à ce nombre non pas sur une requête, mais à la fin de la journée, donc cela veut dire que cela vaut la peine de faire cette démarche dans une boucle appelée souvent ou dans le cœur d’un framework (qui va être installé sur de nombreuses machines). Sinon, dans la logique métier d’une application, il y aura assurément beaucoup de points optimisables avant d’optimiser ces appels.

Conclusion, vous pouvez manger des namespaces, ils ne sont pas beaux à voir mais ils sont bons.

Pour info, le code :

<?php
namespace speedtest
{
    function testfallback()
    {
        return strlen('qwieuqhwiuhdqwiuh');
    }
    function testdirect()
    {
        return \strlen('qwieuqhwiuhdqwiuh');
    }
}
namespace 
{
    $resf = array();
    $resd = array();
    for ($j=0;$j<100;$j++) {
        $start = microtime(true);
        for ($i=0;$i<1000000;$i++) {
            speedtest\testfallback();
        }
        $stop = microtime(true);
        $start1 = microtime(true);
        for ($i=0;$i<1000000;$i++) {
            speedtest\testdirect();
        }
        $stop1 = microtime(true);
        $resf[] = $stop-$start;
        $resd[] = $stop1-$start1;
    }
    print "Direct: ".(array_sum($resd)/100.0)." ".min($resd)." ".max($resd)." ".sd($resd)."\n";
    print "Fallback: ".(array_sum($resf)/100.0)." ".min($resf)." ".max($resf)." ".sd($resf)."\n";
}

Pirium - The simple PEAR Channel Server Manager

The 2009-11-28 at 09:50 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

Chouette, Fabien Potencier vient de lancer Pirium. Pirium, c’est un petit script simple, puissant et élégant pour la création d’un dépôt PEAR pour vos projets PHP.

Oui, je dis du bien de ce script ! C’est un script qui ne fait pas la vaisselle, qui n’a pas 160 classes et en fait qui fait une chose et j’espère le fait bien. Comme tout ce que j’ai utilisé/vu venant de Fabien faisait du bon travail — souvent trop lourd pour moi, mais au final toujours bon — je ne doute pas que Pirium va faire du bon travail.

Attendez-vous à avoir InDefero et Pluf disponibles via un dépôt PEAR sous peu ! Merci Fabien !

Edit: C’est Pirum et en non Pirium. :-/

Espace de noms dans PHP (namespace)

The 2008-11-03 at 10:15 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

C’est décidé, le séparateur des espaces de noms pour PHP sera \ le "backslash". Cette décision fait couler beaucoup d’encre, particulièrement les personnes trouvant ce caractère trop Windows. Je me rappelle de ma première réaction avec les décorateurs Python commençant par l’arobase @. Je trouvais cela moche et trop Perl à mon goût. Maintenant, je trouve cela normal.

Que cela soit ::, :::, /, , ou n’importe quel autre caractère, l’important est que cela se tape vite, ce qui est le cas, que cela se repère vite dans le code, ce qui est aussi le cas et que mon mode PHP dans Emacs puisse faire la coloration syntaxique correctement, ce qui sera bientôt le cas plus que probablement. Conclusion, on s’y fait fait vite et de toute façon, cela restera en haut de fichier.

The use of the middleware in Pluf

The 2007-02-21 at 15:12 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

The best technical choice I made for the structure of Pluf was to follow the lead of the Django Project. I created Pluf because I really needed to have the Django speed of development on systems where using Python was not an option. This was not an option because I had to implement a solution to be then maintained by people not having the right knowledge. I learnt the hard way in the past that the best technical solution is also the one that can be handled by the people in house.

Ok, back to the topic, what I really enjoyed with Django was that the data are nicely encapsulated with basically:

  • A request object representing the query with GET/POST data.
  • A dispatcher that will call a given view function based on the request URI.
  • A response object created in the view function and sent back to the client.

On top of that you have middleware. Middleware are men in the middle, they take a request object and modify it before giving it to the view, or, take a response object and modify it before giving it back to the client.

At the moment, on the main conference website, I am using 2 middleware, a maintenance middleware and a session middleware.

The session middleware handles session, nothing really new in it and the maintenance middleware is a really small but practical middleware. What it does is that if a MAINTENANCE file is found at a given place on the server, it automatically intercept the request and returns a page telling that the server is in maintenance. Basically, when I want to perform a complex upgrade which cannot be performed fully live, I just go in the right folder and touch MAINTENANCE, perform the upgrade and then remove the file.

But what is really interesting is the ability to modify the response after the view generated it. I have upgraded the Tidy middleware to modify the </body> tag of the page and append just before the log of the errors when running Tidy against the content of the page. It means that now, I do not have to think when the page is not valid, I have the error messages right away! I just take a look at the source of the page, find the error, fix the code, reload the page. It is fast and fun, no need to painfully submit your code to a validator or copy/paste the code to validate it.

When developing, I am using a Debug middleware to display the peak memory usage of the page, the execution time and the database queries. It is very practical to spot the weaknesses in the code. As you can see in the following screenshot, the peak memory is provided using the Xdebug xdebug_peak_memory_usage function and when you click on the DB query # link, you can see all the queries (it is just a little javascript to toggle the visibility style of the <div> containing the queries).

Screenshot of the Pluf debug middleware

Something I often miss in organisations, is that we tend to act a lot based on feelings and not based on factual data. Very often it is easy to gather the data to support your decisions, but people are not doing it. So enjoy the Pluf Middleware to know what is going on in your code and improve based on real data.

Solar PHP framework

The 2007-01-09 at 16:28 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

The Solar PHP Framework is the framework which helped me to create the Pluf Framework. Pluf is heavily inspired by Django with views, a nice ORM and templating system, but what really kicked out Pluf is the Solar idea (pioneered by PEAR as Paul M Jones reminded me) that when you name a class My_Wonderfull_Class the class will be available in the file My/Wonderfull/Class.php. Then with the power of PHP5 you can create an __autoload function (PHP doc of __autoload) to basically automatically load the class based on its name. End result of the autoload trick:

  • No more include_once nightmare in your code, you load the necessary files and only them.
  • A very clean code layout because you know where the classes are.
  • More freedom when using objects because you know that you do not have to define a priori which objects are going to be loaded, you do not need any complex logic to load the corresponding .php files anymore, you use more objects and your code is cleaner.
  • Clean code, good encapsulation of the logic in classes, your code is now easy to read and maintain.
  • Bingo!

Think about it when starting a project in PHP.

Gettext and PHP, the good, the bad and the hugly

The 2006-12-19 at 15:20 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor.

Yesterday I took a look at gettext to be used in the core of the next version of Plume CMS. I was ready to use it until I discovered some annoying things:

  • You need to have it to use it. Not really a problem as nowadays the gettext extension is installed by nearly all the provider.
  • In some cases, you need to restart Apache to reload the new translations.
  • You need to have the corresponding locale installed on the system to be able to use a given language. That is, if your provider has only the English locale available, sorry, it won’t work.

Check the comments on the gettext PHP manual page to see all the problems you can have. As Plume CMS is supposed to be used in a non controlled environment, I had to find another solution. Looking around, I found a nice gettext benchmark. The results from the benchmark together with the interesting comments can be summarized as:

  • the pure PHP implementation of gettext solving the problems is slow.
  • an array with translation strings is nearly as fast as gettext.
  • loading the translation strings from a .ini like file is convenient, but very slow.

The solution I found is basically to reuse the approach of the current Plume CMS translation system and extend it. At the moment, the translation system does not support plural forms, so I created it. The partial implementation is available in Pluf. Pluf is the MVC framework that will be used as the core of the next release of Plume CMS. Now you can do the following:

// Translate a single string
echo __('Hello World!'); 
// Translate a plural form
echo sprintf(_n('Here is %d apple.', 'Here are %d apples.', $n), $n);

The file storing the translations is an easy to read and write .ini like file and the framework will automatically cache the strings in a dynamically generated PHP file ready for inclusion and parsing by the PHP tokenizer, thus really fast.

Here is an example of a .lang file:

# -*- coding: utf-8 -*-
# (C) 2004-2006 Cédric Arrabie, Loïc d'Anterroches
;Welcome on the Plume CMS installation
Bienvenue sur l'assistant d'installation de Plume CMS

;Next
Suivant

;Nothing to see here.
p;You have some things to see here.
0;Rien à voir ici.
1;Une chose à voir ici.
2;Plusieurs choses à voir ici.

Basically, we will be able to use it like gettext and ngettext. Of course it is a very simple approach and I am not an expert in internationalization, but today Plume CMS is already translated in several languages and this approach is just improving the current approach, so basically translators will be happy (I hope).

PHP Naive Bayesian Filter

The 2008-05-26 at 18:39 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor and Scripts.

Le sujet à la mode est le filtrage des commentaires, pingbacks ou autres trackbacks de votre site. Je ne joue pas trop avec cela, mais le principe d’un filtre reposant sur le théorème de Bayes m’intrigait trop pour résister à une implémentation en PHP.

XULit! CMS

The 2004-02-20 at 16:25 by Loïc d'Anterroches filed under Scripts and PHP: Hypertext Preprocessor.

Le web est pour tous et toutes, même les aveugles. Voilà un CMS qui répond à cette problématique d’accessibilité en ayant tout, de la partie d’administration au site publique par défaut d’accessible.

Utilisation de l'API SOAP de Google en PHP

The 2003-08-11 at 19:07 by Loïc d'Anterroches filed under Scripts and PHP: Hypertext Preprocessor.

L’API SOAP de Google vous permet d’intégrer dans votre site un moteur de recherches avec un simple script PHP. Vous pouvez faire des recherches dans votre site ou dans l’ensemble de la base de Google.

MyBackup, sauvegarde des bases MySQL

The 2003-09-17 at 19:24 by Loïc d'Anterroches filed under Scripts and PHP: Hypertext Preprocessor.

Script PHP simple à mettre en place pour la sauvegarde et la restauration d’un nombre illimité de bases MySQL.

Compteur Live pour un site

The 2004-08-09 at 20:03 by Loïc d'Anterroches filed under PHP: Hypertext Preprocessor and Scripts.

LiveCount est un script PHP et MySQL permettant d’évaluer le nombre de personnes actuellement en ligne sur votre site en temps réel. Les limitations du système sont présentées avec les détails de l’implémentation.


Logo of Plume CMS