mardi, décembre 03, 2024
Nom d'utilisateur : Mot de passe :
[NEWS]
Envoyé par unreal
Optimiser un disque ? Pour quoi faire ?

Les disques de la série Advanced Format WD ont une particularité intéressante : ils utilisent des secteurs physiques de 4ko au lieu des 512 octets habituels, taille utilisée depuis maintenant 30 ans. Pour assurer la compatibilité avec les systèmes existants (utilisant toujours 512 octets comme taille de secteur logique), le micro logiciel embarqué dans le disque réalise une opération de mapping. Ainsi, il fait rentrer 8 secteurs logiques dans un seul secteur physique.

Cela fonctionne parce qu'un système d'exploitation n'écrit jamais des blocs aussi petits. En effet, l'OS va poser son système de fichiers sur le disque et ainsi définir une taille minimale de bloc, 16ko par défaut sur UFS, par exemple.

C'est alors qu'on constate un problème potentiel. D'un côté nous avons le système d'exploitation qui veut écrire des blocs de 16ko, de l'autre nous avons un disque qui dispose de secteurs de 4ko, le tout communiquant sur un bus de 512 octets. Dans ce cas, il peut avoir un décalage faisant en sorte qu'un bloc du système de fichier soit écrit physiquement sur 5 secteurs au lieu de 4 :

aligning.png


Il se produit alors une dégradation des performances à deux niveaux :

  • Lors des lectures, le disque doit lire 5 secteurs au lieu de 4
  • Lors des écritures, le disque doit d'abord lire les deux secteurs incomplets, calculer l'intersection avec les nouvelles données, puis ré-écrire les 5 secteurs



Test de débit avec formatage par défaut

Commençons par créer une nouvelle partition en suivant le Handbook FreeBSD, à savoir :

# dd if=/dev/zero of=/dev/ad10 bs=1k count=1
# bsdlabel -Bw ad10 auto
# bsdlabel -e ad10
# newfs /dev/ad10
# mount /dev/ad10a /mnt/temp


Une fois la partition créée et montée, il suffit de lancer Bonnie++ dans un dossier quelconque et d'analyser les résultats.

On constate que les performances sont inférieures aux attentes, indiquant potentiellement un mauvais alignement par rapport aux secteurs physiques.


Recherche du meilleur offset

Pour trouver l'alignement optimal, on recommence l'expérience précédente plusieurs fois en changeant l'offset. Il est également intéressant de faire un test d'écriture avec dd avant le test Bonnie, puis un test de lecture après pour comparer.

Pour réaliser ces mesures je me suis basé sur la configuration suivante :
  • Disque WD15EARS (1.5To avec 64Mo de cache)
  • Carte mère Intel DG965SS (ICH8)
  • FreeBSD 8.0p2
  • Bonnie++ v1.96 en procédant systématiquement à deux mesures
  • Taille de bloc UFS = 4ko (newfs -b 4096 -f 512)


Le graphe suivant résume les résultats :

offsetgraph.png


Le graphe montre clairement que l'alignement est assuré par défaut, contrairement à ce qu'on pouvait soupçonner. En effet, les meilleures vitesses en écriture sont obtenues avec un offset de 16 (défaut), puis avec un offset de 24, c'est-à-dire avec un offset supplémentaire de 4ko. Il est intéressant de noter que les performances en lecture séquentielle sont assez peu impactées par un mauvais alignement et on peut penser que c'est grâce au cache du disque qui contient forcément les secteurs lus récents, évitant ainsi une 2ième lecture.

Du coup, nous voilà pas spécialement plus avancés pour trouver l'origine des performances décevantes.


Une autre piste : la taille des blocs

Par défaut UFS utilise une taille de bloc de 16ko, ce qui semble en première approche convenable. Hélas ce n'est pas aussi simple : utiliser des blocs de 16ko implique une taille de fragments de 2ko parce qu'il est conseillé de préserver un rapport de 1/8. Selon le site de Sun, les fragments sont utilisés pour minimiser la fragmentation du système de fichiers en allouant des fragments de blocs plutôt que des blocs complets quand il n'en y a pas besoin.

Le problème est que ce disque WD ne sait pas écriture directement des blocs de 2ko, ayant lui-même des blocs de 4ko.

Pour étudier l'influence de la taille de bloc sur les performances, j'ai réalisé des benchmarks avec différentes tailles de blocs :

blocksizegraph.png


Il en ressort, sans surprise, qu'une taille de bloc de 32ko est bénéfique sur les performances, surtout que cela permettra au système de fichiers d'écrire systématiquement des blocs >= 4ko.


Conclusion

Contrairement à mes craintes initiales, l'alignement des secteurs est bien assuré si on opte pour un formatage natif. Par contre, il est intéressant d'augmenter la taille de blocs à 32ko en UFS parce que :
  • Cela augmente les performances séquentielles
  • Cela garantit une taille de fragment de 4ko



Historique

08/03/2010 - Version initiale

Posté le 03/03/10 à 18:58 - 0 Commentaires...

[NEWS]
Envoyé par unreal
Le SheevaPlug est un engin marrant. Dans un boitier de la taille d'un bloc secteur 220 Volts, il embarque un ordinateur complet, idéal pour réaliser serveur de fichiers, concentrateur VPN, firewall, petit serveur Web, bureau à distance ou point d'accès Wifi, les possibilités sont illimitées. Surtout dans la mesure où le Sheeva consomme moins de 3 Watts à vide et 7 Watts en pleine charge.

Grâce à cet article vous allez pouvoir netbooter votre SheevaPlug en FreeBSD, afin de préparer un environnement applicatif, qui pourra être migré ensuite sur flash pour rendre le boitier autonome.

Mais avant toute chose, voyons de quoi il s'agit.


Sommaire



Présentation de la bête

IMG_2589.jpg
Un SheevaPlug qui rode sur ma table de salon



Extérieurement on dispose de la connectique suivante :
  • Un port Ethernet cuivre gigabit
  • Un port USB 480Mbit/s
  • Un port mini USB JTAG/console série
  • Un port SD compatable SDHC
  • Un bouton reset
  • Pas de port VGA


Et dedans :
  • Un SoC Marvell Kirkwood à 1.2GHz
  • 512Mo de DDR2 400MHz
  • 512Mo de flash NAND
  • Alimentation à découpage compatible 100-240VAC


Et tout ça pour $99 (+frais de port) via le partenaire de Marvell.

C'est clairement un jouet idéal pour geek qui a envie de s'initier au monde du hardware embarqué à moindre frais.


Pré-requis

Afin de monter la maquette vous aurez besoin des éléments suivants :
- Un serveur de build sous FreeBSD, non nécessairement ARM. J'ai utilisé la configuration suivante :

# uname -a
FreeBSD nas.localdomain 7.2-RELEASE-p3 FreeBSD 7.2-RELEASE-p3 #0: Sat Aug 1 14:51:14 CEST 2009     root@nas.localdomain:/usr/obj/usr/src/sys/GENERIC amd64


Vous n'allez vraiment pas vouloir builder directement sur le SheevaPlug !

- Un serveur TFTP
- Un serveur DHCP (attention, il doit être configurable !)
- Un serveur NFS sous FreeBSD

Par mesure de simplicité, il est supposé dans cet article que serveur de build, TFTP et NFS sont regroupés sur une seule machine.


Préconfiguration

Dans ce paragraphe, nous allons configurer plusieurs éléments essentiels de la maquette.

Serveur TFTP

Préparer un dossier qui servira de root TFTP :
mkdir -p /home/tftp/sheevaplug


Ensuite éditez /etc/inetd.conf et activez le serveur TFTP :
tftp    dgram udp     wait    root    /usr/libexec/tftpd     tftpd -l -s /home/tftp


Il ne reste plus qu'à relancer inetd :
/etc/rc.d/inetd restart


Serveur NFS

Préparer un dossier qui servira de root NFS diskless :
mkdir -p /home/diskless/sheevaplug


Editez ensuite /etc/exports pour déclarer le nouveau share NFS :
/usr/home/diskless/sheevaplug -maproot=0:0    1.2.3.4


Remplacez 1.2.3.4 par l'IP ou nom résolvable du SheevaPlug.

Démarrez ou redémarrez le service NFS selon les instructions du Handbook.

Serveur DHCP

Le serveur DHCP sert à paramétrer le point de montage root (/) pendant le boot de l'OS. Editez votre fichier de configuration DHCPd, généralement dhcpd.conf, pour définir un host statique, par exemple :

host sheevaplug {
        hardware ethernet 00:50:43:01:67:d0;
        fixed-address 1.2.3.4;

        # Netboot stuff.
        option tftp-server-name "1.2.3.5";
        filename "sheevaplug/kernel.bin";
        next-server 1.2.3.5;
        option root-path "/usr/home/diskless/sheevaplug/";
}


Remplacez 1.2.3.4 par l'IP du SheevaPlug et 1.2.3.5 par l'IP du TFTP/NFS.


Build FreeBSD

Passons maintenant aux choses sérieuses. Utilisez csup pour télécharger les sources de FreeBSD 8.0 (en RC1 au moment où j'écris ces lignes) ; si vous disposez déjà des sources d'une version antérieure, je vous conseille de supprimer /usr/src avant de lancer csup.

Vous pouvez utiliser le fichier de configuration suivant pour csup :

*default host=cvsup3.fr.FreeBSD.org
*default base=/usr
*default prefix=/usr
*default release=cvs tag=RELENG_8
*default delete use-rel-suffix
*default compress
src-all
src-sys
src-base


Avant de lancer le build proprement dit, un peu de théorie. Si vous avez lu la documentation du CPU 88F6281, vous aurez certainement constaté ceci :

- 16KB-Instruction and 16KB-Data 4-way, set-associative L1 cache
- 256KB unified 4-way, set-associative L2 cache


256ko de cache L2 est très faible par rapport aux 2-12Mo des CPU Intel modernes et va clairement conditionner les options de compilation que nous allons utiliser. Si vous avez un peu l'habitude de compiler sur du Intel, vous avez peut-être envie d'utiliser des options du type CFLAGS= -O2 -pipe -fomit-frame-pointer -funroll-loops mais clairement il ne faut pas utiliser des options de ce type sur un CPU avec aussi peu de cache L2. Nous allons donc opter pour CFLAGS= -Os -pipe pour générer du code plus petit afin qu'il rentre plus aisément dans le cache L2 du CPU.

Editez donc /etc/make.conf pour fixer les options de compilation :

# For building Sheeva/ARM
CFLAGS= -Os -pipe -w
.if ${.CURDIR:M*/lib/libstand*}
CFLAGS= -O -pipe -w
.endif


Le bloc if...endif sert à définir d'autres options de compilation quand -Os ne fonctionne pas.

Lancez ensuite le build :

$ su -
# DESTDIR=/usr/home/diskless/sheevaplug
# TFTPDIR=/usr/home/tftp/sheevaplug
# cd /usr/src
# rm -rf ../obj
# export DESTDIR
# make buildworld TARGET_ARCH=arm
# make installworld TARGET_ARCH=arm
# make distrib-dirs TARGET_ARCH=arm
# make distribution TARGET_ARCH=arm
# make buildkernel TARGET_ARCH=arm KERNCONF=SHEEVAPLUG
# mv $TFTPDIR/kernel.bin $TFTPDIR/kernel.bin.old
# cp /usr/obj/arm/usr/src/sys/SHEEVAPLUG/kernel.bin $TFTPDIR


Vérifiez à chaque étape qu'il n'y a pas d'erreur. A la fin vous aurez :
- L'image de boot tftp dans /usr/home/tftp/sheevaplug
- Le root NFS dans /usr/home/diskless/sheevaplug

Pour finir, préparer la configuration pour utilisation sans disque :

# echo 'hostname="sheevaplug"' > $DESTDIR/etc/rc.conf
# echo 'sshd_enable="YES"' >> $DESTDIR/etc/rc.conf
# echo 'rpcbind_enable="YES"' >> $DESTDIR/etc/rc.conf
# echo 'nfs_client_enable="YES"' >> $DESTDIR/etc/rc.conf
# echo 'rpc_lockd_enable="YES"' >> $DESTDIR/etc/rc.conf
# echo 'rpc_statd_enable="YES"' >> $DESTDIR/etc/rc.conf
# echo 'ntpdate_enable="YES"' >> $DESTDIR/etc/rc.conf
# echo 'ntpdate_flags="europe.pool.ntp.org"' >> $DESTDIR/etc/rc.conf



Configuration de la console série

Le configuration console du SheevaPlug se fait via le mini port USB qu'on voit sur la photo de début d'article. En interne, ce port est relié à un FT2232C qui émule un port série sur USB. L'avantage de ce chipset est qu'il est correctement supporté par divers systèmes d'exploitation, mais le problème ici est qu'il présente un VID/PID (vendor ID et product ID) qui ne sont absolument pas reconnus par les drivers supportant le chipset FT2232C. Je vous conseille donc l'utiliser Linux pour accéder à la console série parce qu'il est possible de forcer VID/PID assez simplement :

rmmod ftdi_sio
modprobe ftdi_sio vendor=0x9e88 product=0x9e8f

Plus d'informations sur cette page.

Utilisez ensuite l'émulateur de votre choix pour accéder au device série, /dev/ttyUSB1 si vous utilisez Linux, par exemple Screen, Nanocom ou Minicom. Rebootez le SheevaPlug et vous devriez voir le loader U-boot qui s'initialise :

uboot.png
U-Boot en cours d'initialisation



Configuration U-Boot

U-Boot est un projet intéressant, même si apparemment le code source est un peu onéreux.

Il supporte plusieurs choses :
  • Boot sur flash NAND interne
  • Boot sur disques mass storage
  • Boot réseau (TFTP/NFS)
  • Les systèmes de fichiers EXT, FAT, et FFS/UFS (moyennant patchs)
  • Aide en ligne
  • Auto-complétion des commandes
  • Enchaînement d'actions
  • Création de scripts
  • Client DHCP


Nous allons utiliser U-Boot pour télécharger une image de boot en mémoire (à l'adresse 0x00900000) et de l'exécuter.

Démarrez le SheevaPlug et appuyez sur une touche pour interrompre le boot. La commande printenv liste la configuration actuelle :

Marvell>> printenv
baudrate=115200
loads_echo=0
console=console=ttyS0,115200 mtdparts=nand_mtd:0xc0000@0(uboot)ro,0x1ff00000@0x100000(root)
CASset=min
MALLOC_len=1
ethprime=egiga0
bootargs_root=root=/dev/nfs rw
[...]


Il peut être intéressant de réaliser une sauvegarde avant modification.

La commande setenv permet de modifier une variable. Nous allons l'utiliser pour éditer les paramètres de boot :

setenv netmask 255.255.255.0
setenv ipaddr 1.2.3.4
setenv serverip 1.2.3.5
setenv image_name sheevaplug/kernel.bin
setenv rootpath /usr/home/diskless/sheevaplug
setenv loadaddr 900000
setenv bootcmd 'tftpboot $(loadaddr) $(image_name); go $(loadaddr)'
saveenv


Remplacez les deux IP par celles de votre configuration. La commande saveenv enregistre la configuration en mémoire flash.

La commande boot démarre le système à partir du shell :

freebsd_boot.png
FreeBSD en cours de Netboot


Après son amorçage, le kernel montera le partage NFS spécifié par DHCP et lancera /sbin/init qui permettra au système de démarrer complétement. A ce stade, il existe un bug que je n'ai pas été en mesure de comprendre : le kernel passe le paramètre "-s" à init qui démarre alors en mode single user :

start_init: trying /sbin/init
Enter full pathname of shell or RETURN for /bin/sh:


Il est possible de quitter le mode single user avec ^D, ou en modifiant le code source d'init :

/usr/src/sbin/init/init.c
        while ((c = getopt(argc, argv, "dsf")) != -1)
                switch (c) {
                case 'd':
                        devfs = 1;
                        break;
                /*case 's':
                        initial_transition = single_user;
                        break;*/
                case 'f':
                        runcom_mode = FASTBOOT;
                        break;
                default:
                        warning("unrecognized flag '-%c'", c);
                        break;
                }



Pour finir

Il reste quelques dernières choses à faire. Modifiez la timezone :

cp /usr/share/zoneinfo/Europe/Paris /etc/localtime


Si vous prévoyez d'installer des ports compilés localement, éditez /etc/make.conf :

CFLAGS=-march=armv5te -Os -pipe


Dans un prochain dossier, j'expliquerai comment migrer cet environnement NFS vers un disque local.


Sources

Divers sites ont servi pour réaliser ce dossier ; les voici dans un ordre quelconque :



Historique

- 15 octobre 2009 : version initiale
- 20 septembre 2010 : liens périmés

Posté le 14/10/09 à 22:40 - 0 Commentaires...

[NEWS]
Envoyé par unreal
Par exports successifs, il est possible que vous ayez affaire un jour à une base MySQL mélangeant plusieurs charsets (latin1 et UTF-8 par exemple). Ce dossier a pour but de vous aider à réparer une telle base avec un effort minimal.

Dans cet exemple nous supposons que le but est d'obtenir une base homogène en latin1 (iso) et que votre base ne contient que des champs 'texte' (pas de BLOB).

Commencez par régler votre console en UTF-8 si ce n'est pas déjà fait :

$ export LANG=en_US.UTF-8


Vérifiez que vous pouvez bien écrire des caractères accentués ; il se peut que vous ayez besoin également de configurer le terminal en UTF-8.

Utilisant mysqldump, exportez la ou les tables à réparer :

$ mysqldump -u root -p --default-character-set=latin1 <nom de base> <nom de table> > /tmp/dump.sql


Vous allez maintenant utiliser sed pour remplacer les caractères en UTF-8 par l'équivalent en ISO :

$ cat /tmp/dump.sql | sed \
-e "s/à/`echo -n 'à' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/é/`echo -n 'é' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/è/`echo -n 'è' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/ê/`echo -n 'ê' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/ë/`echo -n 'ë' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/î/`echo -n 'î' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/ô/`echo -n 'ô' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/ù/`echo -n 'ù' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/ç/`echo -n 'ç' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/À/`echo -n 'À' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/É/`echo -n 'É' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/È/`echo -n 'È' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/Ê/`echo -n 'Ê' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/Ë/`echo -n 'Ë' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/Î/`echo -n 'Î' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/Ô/`echo -n 'Ô' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/Ù/`echo -n 'Ù' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" \
-e "s/Ç/`echo -n 'Ç' | iconv --from-code=UTF-8 --to-code=ISO-8859-15`/g" > /tmp/dump-1.sql


Il ne reste plus qu'à ré-importer :

mysql -u root -p <nom de base> < /tmp/dump-1.sql


Historique :
- 20090831 : version initiale

Posté le 31/08/09 à 15:10 - 0 Commentaires...

[NEWS]
Envoyé par unreal
Il y a plusieurs cas qui justifient de configurer Apache pour modifier les entêtes des fichiers servis, par exemple :

- Vous hébergez un site très fréquenté et vous voulez réduire les requêtes successives sur les mêmes images, js, fichiers de style et pages statiques qui ne changent que rarement
- Vous avez une application Web qui envoie des entêtes de cache, mais vous voulez écraser la valeur envoyée sans modifier l'application
- Vous utilisez IE6 comme navigateur et vous souhaitez lui imposer un comportement de cache moins aléatoire

Apache propose plusieurs façons de gérer le cache des fichiers servis. Le premier est via le module mod_expires, par exemple :

LoadModule expires_module modules/mod_expires.so
...
ExpiresActive On
ExpiresByType image/gif A86400
ExpiresByType image/jpeg A86400
ExpiresByType image/png A86400


Dans cet exemple, le navigateur gardera les images en cache pendant une journée avant de re-télécharger. L'inconvénient de cette méthode est que mod_expire n'écrase pas les entêtes ; si l'application qui génère les images a déjà appliqué une politique de cache, celle-ci restera.

Si le but est d'écraser, il existe une autre façon, via mod_headers, par exemple :

LoadModule headers_module modules/mod_headers.so
...
<Location ~ "\.(gif|jpe?g|png)$">
    Header set Cache-Control "max-age=86400"
</Location>


Cet exemple est comparable au précédent en termes de fonctionnalité, sauf que les entêtes de même nom seront écrasées cette fois-ci.

La directive « Header » supporte plusieurs actions :

- set : remplace l'entête de même nom
- append : ajoute à l'entête de même nom
- merge : complète l'entête de même nom
- add : duplique l'entête (déconseillé)
- unset : enlève l'entête
- echo : copie l'entête de requête dans la réponse
- edit : permet d'éditer l'entête via des RegEx

Conclusion : vous avez maintenant la possibilité de gérer vos entêtes de cache aux petits oignons !

Posté le 26/02/09 à 15:50 - Commentaires désactivés

[NEWS]
Envoyé par unreal
Article que j'ai initialement écrit pour une mailing list, que je poste aussi, du coup...

A titre personnel, je gère quelques serveurs relativement modestes
hébergeant des sites Web à forte fréquentation. Je devais donc
concevoir une plate-forme à la fois performante, robuste et sécurisée
afin d'héberger des applicatifs PHP (mais on peut facilement
s'inspirer de cet article pour héberger d'autres langages).

La motivation de cet article vient de la constatation que la
configuration par défaut sur tous les systèmes Linux/BSD que j'ai pu
croiser était horriblement inadaptée à des besoins modernes
d'hébergement d'applications "web 2.0" à forte charge.


Choix d'un serveur Web

Un certain nombre d'administrateurs systèmes ont abandonné Apache au
profit Lighttpd pour des raisons de performances, mais la vérité est
que les deux peuvent convenir moyennant optimisation et configuration.
Pour ma part, je préfère utiliser Apache pour servir des pages Web, et
éventuellement ajouter un Lighttpd pour servir du contenu purement
statique (fichiers de style, JS, images...).

Quelques considérations quant à la configuration Apache :

  • Mode prefork à éviter
  • Enlever les modules inutilisés
  • Ne plus configurer PHP en module


Depuis la version 2.0, Apache est multithreadé, ce qui veut dire qu'un
seul processus peut gérer plusieurs connexions, avec un gain de
mémoire impressionnant. Par ailleurs, il convient aussi de faire le
tri dans les modules Apache, ou mieux, compiler un Apache répondant au
mieux à ses besoins. Ca peut surprendre de vouloir encore compiler
alors qu'il existe des paquetages, mais un autre avantage c'est que
cela permet aussi de migrer de version avec zéro downtime : il suffit
de compiler la nouvelle version en modifiant le '--prefix', de copier
la config, de démarrer sur un autre port pour tester, et de modifier
un symlink quand c'est prêt.

Exemple de compilation Apache :

export CFLAGS=...
export CXXFLAGS=...

./configure \
--prefix=/usr/local/apache224 \
--enable-log_config=shared \
--enable-mime=shared \
--enable-status=shared \
--enable-autoindex=shared \
--enable-dir=shared \
--enable-cgi=shared \
--enable-alias=shared \
--enable-access=shared \
--enable-auth=shared \
--enable-expires=shared \
--enable-rewrite=shared \
--enable-dav=shared \
--enable-proxy=shared \
--with-mpm=worker


Pour en finir avec Apache, PHP n'est pas encore "thread safe" donc,
une utilisation en module est à éviter ; nous utiliserons alors le
mode CGI.


Choix d'un connecteur CGI

Bien qu'il soit tout à fait possible d'utiliser PHP comme CGI
directement, cette méthode présente l'inconvénient majeur de lancer le
binaire PHP à chaque accès à une page dynamique. Le coût CPU est donc
prohibitif sur un serveur à fréquentation importante.

Il convient alors d'utiliser un connecteur de type "FastCGI", et j'ai
une très nette préférence pour FCGID pour
plusieurs raisons :

  • Efficacité : module maintenu et conçu pour Apache 2.x alors que
    FastCGI n'est plus maintenu
  • Stabilité : FCGID dispose d'un watchdog pour surveiller l'état des
    workers
  • Configuration : FCGID propose des options de configuration fines


Concrètement, le connecteur FastCGI maintient une pool de "workers"
PHP et transmet à un worker libre quand une requête arrive, tout en
recyclant les processus de manière à éviter qu'un processus reste trop
longtemps en service.


Optimisation PHP

Avant toute chose, il convient d'installer une version de PHP
compatible FastCGI, ou mieux : compiler sa propre version, ce qui
présente un avantage de taille, il est possible de mettre à jour PHP,
sans downtime, et sans même relancer Apache. En effet, FCGID va
recycler périodiquement les "workers" PHP, du coup, il suffit de faire
pointer le symlink vers la nouvelle version et au prochain recyclage,
la nouvelle version sera active.

Exemple de compilation PHP compatible FastCGI :

export CFLAGS=...
export CXXFLAGS=...

./configure \
--prefix=/usr/local/php524 \
--with-mysql=/usr/local/mysql \

[...]

--enable-force-cgi-redirect \
--enable-fastcgi


Pour ce qui est de l'optimisation PHP, outre la possibilité de
fouetter ses développeurs ( wink.gif ), il convient d'installer un logiciel
de cache. Il en existe plusieurs (eAccelerator, Turck MMCache...), et
ils se présentent sous la forme d'une extension PHP.

Mon préféré à ce jour est Xcache parce
qu'il supporte parfaitement les environnements Linux/BSD que
j'utilise, est assez facile à configurer (quelques lignes dans
php.ini) et offre un excellent niveau de stabilité.


Gestion d'utilisateurs avec Suexec

Suexec est un peu le "sudo" du serveur Web : il permet d'exécuter des
applications CGI sous un autre utilisateur que l'utilisateur du
serveur Web (qui est souvent "www", "www-data" ou "apache").

Cela est surtout intéressant en hébergement mutualisé où il permet
d'isoler les utilisateurs (droits sur le disque, invisibilité de
processus, ainsi de suite), d'identifier rapidement un utilisateur qui
pose problème et d'éviter les casse-tête au niveau des droits.

Pour supporter cette fonctionnalité, Apache doit être compilé en
conséquence :

./configure \
[...]
--enable-suexec=shared \
--with-suexec-caller=www \
--with-suexec-docroot=/usr/local/www/cgi \
--with-suexec-uidmin=1000 \
--with-suexec-gidmin=1000


Ensuite, chaque utilisateur doit avoir son CGI dédié (ici le binaire
"php-cgi" compilé avec support FastCGI), dont il est propriétaire.
Attention : il faut réellement un binaire dédié, pas un symlink.

Par exemple :

/usr/local/www/cgi/user1/php-cgi [user1/user1]
/usr/local/www/cgi/user2/php-cgi [user2/user2]
[...]
/usr/local/www/cgi/userN/php-cgi [userN/userN]
[...]


Et pour finir, il suffit dans chaque virtual host de déclarer quel
binaire doit être chargé :

<Directory "/home/userX/www">
        <IfModule fcgid_module>
             FCGIWrapper /usr/local/www/cgi/userX/php-cgi .php
        </IfModule>
</Directory>

<VirtualHost *:80>
        ServerName domaine.fr
        ServerAlias www.domaine.fr
        DocumentRoot /home/userX/www
        CustomLog /home/userX/logs/access.log combined
        SuexecUserGroup userX userX
</VirtualHost>



Exemple de configuration

Voici un exemple de configuration Apache sans Suexec. Pour la
configuration avec, il suffit de prendre les indications du paragraphe
précédent !

LoadModule fcgid_module modules/mod_fcgid.so
[...]
<Directory "/usr/local/www">
        Options FollowSymLinks ExecCGI

        <IfModule fcgid_module>
                FCGIWrapper /usr/local/php5/bin/php-cgi .php
        </IfModule>
</Directory>

# fcgid config
<IfModule fcgid_module>
        IPCConnectTimeout         10
        IPCCommTimeout            40
        MaxRequestsPerProcess 500
        ProcessLifeTime             600
        MaxProcessCount         100
        SocketPath                     sock/fcgidsock
        SharememPath             sock/fcgid_shm
</IfModule>

[...]
<IfModule mime_module>
        [...]
        AddHandler fcgid-script .php
</IfModule>



Conclusion

Ce petit article/howto avait comme objectif d'explorer les
améliorations suivantes en hébergement Web :
  • Performances (processus légers, caches)
  • Sécurité (Suexec)
  • Stabilité (workers séparés avec surveillance)


J'espère qu'il vous a plu !

Posté le 27/03/08 à 11:37 - 3 Commentaires...

2 pages... [1-5][6-10]