Compression avant transfert

Après avoir parlé de minimisation, il est temps de parler de compression, la règle 4 des recommandations de l’équipe performance Yahoo!.

Trop gros

Une part importantes des téléchargements sont réalisés sur de simples fichiers textes : HTML, javascript, CSS, XML et JSON. Mis côte à côte ils peuvent représenter un poids non négligeable. C’est particulièrement vrai avec les bibliothèques javascript récentes. On dépasse alors les 50 ko pour la base, et plus si on ajoute les composants optionnels.

Un site classique avec Jquery c’est 25 ko pour le HTML, 10 ko pour les feuilles de style, 100 ko pour la bibliothèque javascript et encore bien 10 ko pour les fichiers javascript qui utilisent cette bibliothèque. La minification nous fait tomber respectivement à 15, 7, 50 et 6 ko, mais le total reste encore proche des 80 ko.

Compresser avant envoi

Tout est prévu, et il est possible de compresser nos fichiers avant de les envoyer, puis de les faire décompresser avant affichage par le navigateur. Cette fonctionnalité est gérée par une écrasante majorité des serveurs web et quasiment tous les navigateurs depuis Microsoft Internet Explorer 4.

Lors de la transmission, c’est un fichier texte compressé qui est échangé. On peut compter que le poids est facilement divisé par deux sur un fichier qui a été minimisé au préalable mais ça peut aller jusqu’à un dixième du poids d’origine. 40 ko d’épargné, ce n’est pas la réussite de l’année mais ça reste appréciable.

Auto-négociation

Tout ça se base sur l’auto-négociation HTTP. Votre navigateur déclare qu’il sait gérer la compression avec une entête Accept-encoding: gzip. Le serveur la détecte, compresse son fichier HTML, et le renvoie avec une entête Content-Encoding: gzip. Tout est transparent pour l’utilisateur ou le navigateur. Si votre navigateur ne supporte pas la fonctionnalité, il n’enverra pas l’entête et recevra le contenu sans compression.

Pour les proxy les plus simples, ceux qui ne (dé)compressent pas les contenus en temps réel, le serveur ajoute une entête Vary: Accept-encoding. Le cache de ce contenu ne sera partagé que entre les navigateurs qui envoient la même entête Accept-encoding (c’est à dire quasiment tous).

L’auto-négociation fait très bien son travail. Il ne vous reste plus qu’à exclure les rares vieux navigateurs qui déclarent supporter la compression mais ont quelques bugs gênants. Si vous détectez ces navigateurs avec un support cassé vous pouvez ajouter Vary: Accept-encoding, User-Agent

Quels fichiers

On compresse ainsi tout ce qui est fichier texte. On évite les images non vectorielles, qui sont en général déjà compressées avec des algorithmes spécifiques, ainsi que les fichiers binaires,  certains comme les fichiers OpenOffice sont déjà le résultat d’une compression et les autres ont trop souvent un taux de compression assez faible.

Un tri très rapide peut être fait à partir des types mime des fichiers : on compresse tout ce qui est en text/* et on laisse le reste tel quel, en particulier les images. Si vous voulez faire de la gestion fine vous pouvez aussi compresser les fichiers Microsoft Office .doc, .ppt et .xls (qui se compressent très bien).

Quel format et quel module

Il y a deux formats de compressions pour HTTP, tous deux supportés correctement : gzip (RFC 1951 et 1952), deflate (RFC 1951 et 1950) et compress. Ce dernier est pour ainsi dire inutilisé dans les échanges Web. Les deux autres sont à peu près équivalents. Pour être précis gzip est simplement du deflate avec quelques meta-données.

Pour le serveur web Apache, cela se traduit dans deux modules : mod_gzip et mod_deflate. Le premier est habituel sous Apache 1.3, le second par défaut est fourni avec Apache 2.0. Les performances sont similaires, même si l’algorithme utilisée par mod_gzip donne des fichiers légèrement plus petits (mod_deflate utilise la bibliothèque système zlib alors que mod_gzip utilise son propre code). La différence entre les deux se joue plutôt sur les fonctionnalités des implémentations des deux modules. Mod_gzip propose en effet quelques possibilités en plus.

Pour IIS j’ai vu passer des liens vers zipenable et httpZip mais il semble qu’un support soit inclus par défaut. PHP a aussi la directive de configuration zlib.output_compression pour compresser son résultat avant l’envoi au navigateur, mais il est probablement plus cohérent de passer par le serveur web pour gérer de genre de questions.

Les performances

Pour le client c’est entre 50 et 90% du traffic réseau sur les fichiers textes et Microsoft Office qui est épargné. Tout cela n’est bien entendu pas neutre pour le serveur. On parle souvent de 5% d’occupation processeur pour compresser les contenus. Donner un chiffre est hasardeux car cela dépend trop du serveur, du matériel, des fichiers à compresser et de la charge cpu.

Il est pourtant possible de dire que la charge supplémentaire ne sera pas très importante en regard du gain réseau. C’est d’autant que le traffic réseau est cher, la puissance processeur ne l’est plus tant que ça. Si vous vous contentez des fichiers textes et fichiers Microsoft Office, que vous ne lancez pas de compression pour des fichiers trop petits (1ko) ou (pour mod_gzip) des fichiers trop gros, vous avez peu de chance de faire des contre-performances.

La configuration et les options

Pour vous aider sur mod_gzip et mod_deflate vous avez la possibilité de préciser un niveau de compression avec neuf valeurs prédéfinies de 1 une compression minimum à 9 pour une compression maximum. Il est souvent conseillé de se fixer entre 4 et 6. Monter à 9 occupe beaucoup le processeur pour une différence de taille minime. Aux valeurs les plus faibles votre serveur n’est quasiment pas occupé mais le gain de taille est déjà visible.

Pour ceux qui ont le plus gros traffic d’autres stratégies sont possibles. Les fichiers compressés peuvent être stockés sur le disque pour éviter d’être recalculés à chaque accès par exemple. Il est même possible de pré-compresser les fichiers et opérer à l’inverse : faire faire décompresser les fichiers au serveur pour les quelques rares navigateurs qui ne savent pas gérer la compression.

Et vous ?

Un doute sur votre serveur ? deux pages en ligne vous permet de tester votre site : le mod_gzip_test et le gzip_test. Faites bien attentions aux résultats de Firebug qui peuvent être modifiés par votre proxy, votre anti-virus, vos anti-spyware, vos pare-feux, vos extensions et les outils de protection de la vie privée que vous pourriez avoir : tout ça peut intervenir avant Firebug et décompresser le flux pour le filtrer avant de le renvoyer.

Vous avez aussi compression test et bandwith calc de port80. Le premier télécharge une page et calcule le gain que vous auriez si le contenu était compressé. Avec cette mesure, le second outil vous permet de calculer les économies sur la facture réseau. C’est là que vous verrez vite si échanger du réseau contre du processeur est intéressant ou pas.

Publié par edaspet

Plus d'informations sur mon profil en ligne

3 réponses sur « Compression avant transfert »

  1. « PHP a aussi la directive de configuration zlib.output_compression pour compresser son résultat avant l’envoi au navigateur… »
    Mon hébergeur (Hostgator) n’a pas mod_deflate activé mais zlib l’est. Ça oblige a appelé les .js et .css en php (ça tombe bien on peut ainsi aussi paramétrer les cache_expire). Je pense que Hostgator préfère (encore?) économiser de l’occupation processeur plutôt que de la bande passante. Mais tant pis pour ceux qui ne le savent pas…
    Super site depuis hier je le dévore…
    MERCI pour toutes ces infos.

  2. Disons que dans tout ce blog je pars du principe que tu as les sous pour faire les changements. Si tu ne les as pas, à toi de faire en fonction de ce que tu peux te permettre.

    Mais si tu as les finances, ajouter du cpu ou des serveurs est toujours réalisable.

    Sinon tu peux pré-compresser tes fichiers, ou stocker la version compressée en cache applicatif, et donc continuer à envoyer des contenus compressés sans pour autant charger le cpu. Dans le temps jpcache faisait ça en PHP.

Les commentaires sont fermés.