Archives pour la catégorie ‘Hébergement’

Load Impact : tester en ligne la montée en charge d’un site web

LoadImpact est un outil en ligne permettant de tester rapidement la montée en charge d’un site web.

Voici les résultats que j’obtiens sur ce serveur :

Niveau configuration :

  • CPU Intel Core2Duo 2 x 2.33Ghz
  • RAM 2 Go
  • OS FreeBSD 8.1 64 bits
  • 6 jails dont 1 avec un environnement web dédié à ce blog
  • Nginx 1.0.0 avec exécution PHP par FastCGI
  • PHP 5.3 (PHP-FPM, 4 processus PHP)
  • cache mémoire APC de 64 Mo.

Le graph est quasi linéaire donc niveau matos çà suffit largement.

ez Find : script de démarrage Solr pour Debian

Pour pouvoir lancer l’instance Solr d’eZ Find (extension eZ Publish) au démarrage de votre serveur Debian, voici le script /etc/init.d/solr à mettre en place :

### BEGIN INIT INFO
# Provides:          solr
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the solr server
# Description:       starts solr using start-stop-daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=solr
DESC=Solr

USER=solr
GROUP=solr
SOLR_HOME=/usr/local/solr
PARAMETERS="-jar start.jar"
DAEMON=/usr/bin/java
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

test -x $DAEMON || exit 0

set -e

. /lib/lsb/init-functions

d_start() {
 start-stop-daemon --start --pidfile $PIDFILE --chuid $USER:$GROUP --chdir $SOLR_HOME --background --make-pidfile --exec $DAEMON -- $PARAMETERS
}

d_stop() {
 start-stop-daemon --stop --quiet --pidfile $PIDFILE --name java
 rm -f $PIDFILE
}

d_status() {
 if [ -f "$PIDFILE" ] && ps `cat $PIDFILE` >/dev/null 2>&1; then
 return 0
 else
 return 1
 fi
}

case "$1" in
 start)
 echo -n "Starting $DESC: "
 if d_status; then
 echo "$NAME is already running."
 exit 1
 fi
 d_start
 sleep 1
 if d_status; then
 echo "OK"
 else
 echo "KO"
 exit 1
 fi
 ;;
 stop)
 echo -n "Stopping $DESC: "
 if d_status; then
 d_stop
 sleep 1
 if d_status; then
 echo "$NAME is still running"
 exit 1
 else
 echo "OK"
 fi
 else
 echo " KO"
 fi
 ;;
status)
 if d_status; then
 echo "$NAME is running (PID: `cat $PIDFILE`)"
 else
 echo "$NAME is not running"
 fi
 ;;
 restart|force-reload)
 echo -n "Restarting $DESC"
 d_stop
 sleep 1
 d_start
 echo "."
 ;;
 *)
 echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
 exit 1
 ;;
esac

exit 0

L’installation du serveur Jetty + Solr est effectuée dans /usr/local/src et l’utilisateur solr est utilisé pour exécuter le serveur. Reste à activer la prise en charge du script :

# update-rc.d solr defaults

Squid : bloquer les clients selon leurs User-Agent

En configuration proxy ou reverse-proxy, squid permet par le biais de ses ACL de filtrer les clients pour autoriser/bloquer leurs requêtes selon des points précis. Il peut alors être intéressant de bloquer les user agents non désirés, en les regroupant sous la forme d’une liste, à laquelle il va comparer la valeur fournie par chaque client. Etant donné que l’user agent peut ne pas être renseigné, une ACL  supplémentaire est nécessaire pour vérifier sa présence.

Voici la configuration que j’ai donc dû mettre en place :

acl HAS_USERAGENT browser ^.+$
acl BAD_USERAGENT browser -i "/etc/squid/bad_useragent.txt'

[...]

http_access deny !HAS_USERAGENT
http_access deny BAD_USERAGENT
http_access allow all

La liste des user agent bloqués est de ce type:

# more /etc/squid/bad_usergent.txt
# Misc
^C:
^Skype
^Notepad
^Wget
^ZmEu
woozweb-monitoring
^Shazam
^PS3Update-agent
^MailRuSputnik
^ebay_api
^PPTVUpdate
^EoAgence
^Facebook
^Shasta
^AOLToolbarMetric
^LineUp2
^DING
^ISUA
^android-sports
^sacore
^jupdate
^MPFv
^SCSDK
^DotMacKit
^Android-GData-Calendar
^Kontiki
^SeaPort
^Messenger
^Raptr
^Kontiki
^YahooMobileMessenger
^YahooMobileMail
^Windows-Update-Agent
^Windows-Media-Player
^Windows-RSS-Platform
^MSDW
Microsoft NCSI
^iTunes
^iPhoto
^GrowlHelperApp
^Apple-PubSub
^AppleSyndication
^AppleTV
^CaptiveNetworkSupport
^AntiVir
^AVGINET
^ZoneAlarm
^COMODO Internet Security
^Azureus
^MailRuSputnik

nginx-etag-module : module de gestion des etags pour Nginx

Le protocole HTTP définit un mécanisme de cache par validation des ressources Web : les Entity Tags. Son intérêt est d’autoriser les requêtes conditionnelles afin d’optimiser la gestion de la bande passante des clients et des serveurs Web. Ainsi, à chaque requête, le serveur calcule et ajoute un Etag, matérialisé par un identifiant unique associé à la ressource et à sa version.

En pratique, la première requête envoie le statut HTTP 200 – OK et l’etag calculé par le serveur. Si le client demande à nouveau la ressource et s’il soumet en information l’etag précédent, le serveur est capable de déterminer sa validité. Si les etags matchent, la ressource est à jour côté client et le serveur renvoie un statut HTTP 304 – Content Not Modified sans les données. Les Etags sont donc un moyen simple et fiable de gestion cache des ressources.

Je vais vous présenter le module que j’ai développé pour effectuer ce job sous Nginx : ngx-http-etag-module. Le calcul de l’etag est indépendant du filesystem afin de permettre une utilisation en cluster. A cela, j’y ai couplé une option permettant de forcer le calcul sur un fichier précis, quelque soit la ressource statique demandée. C’est cette raison qui m’a incité à développer ce module, car elle me permet de conserver le cache des proxys frontaux suite à une mise à jour des fichiers. Seul un touch sur le fichier permet d’invalider l’ensemble du cache et propager les modifications.

Installation

$ git clone git://github.com/bhuisgen/nginx-etag-module.git ./nginx-etag-module
Initialized empty Git repository in /private/tmp/nginx-etag-module/.git/
remote: Counting objects: 21, done.
remote: Compressing objects: 100% (21/21), done.
remote: Total 21 (delta 6), reused 0 (delta 0)
Receiving objects: 100% (21/21), 4.62 KiB, done.
Resolving deltas: 100% (6/6), done.
$ cd nginx-etag-module/

Le code de Nginx doit également être récupéré, compilation statique oblige :

$ wget http://nginx.org/download/nginx-0.7.67.tar.gz
--2010-09-03 20:35:46--  http://nginx.org/download/nginx-0.7.67.tar.gz
Résolution de nginx.org (nginx.org)... 81.19.68.137
Connexion vers nginx.org (nginx.org)|81.19.68.137|:80...connecté.
requête HTTP transmise, en attente de la réponse...200 OK
Longueur: 608462 (594K) [application/octet-stream]
Sauvegarde en : «nginx-0.7.67.tar.gz»
100%[===================================================================
=======================>] 608.462     64,9K/s   ds 8,5s
2010-09-03 20:35:54 (70,0 KB/s) - «nginx-0.7.67.tar.gz» sauvegardé [608462/608462]
$ tar xzf nginx-0.7.67.tar.gz
$ cd nginx-0.7.67
$ ./configure --add-module=../

Le script configure doit détecter la présence du module :

adding module in ../
 + ngx_http_etag_module was configured

Comme d’habitude, compilation puis installation :

$ make
$ sudo make install

Configuration

Pour activer la prise en charge des etags :

server {
   listen       8000;
   server_name  localhost;
   root /usr/local/www/html;
   index index.php;

   location / {
      etag on;
   }
   location ~ \.php$ {
      include        fragments/php.conf;
   }
}

Pour rediriger le calcul des etags sur un unique fichier :

server {
   listen       8000;
   server_name  localhost;
   root /usr/local/www/html;
   index index.php;

   location / {
      etag on;
      etag_file /opt/local/var/www/etag_file
   }
   location ~ \.php$ {
      include        fragments/php.conf;
   }
}

Exemple :

PHP : gestion FastCGI avec PHP-FPM

Le port de PHP 5.3.3 est disponible ! Au programme de cette nouvelle version, l’intégration de PHP-FPM, un gestionnaire de processus PHP/FastCGI.

PHP-FPM permet de gérer plusieurs pools de processus, chacun possédant ses propres règles : gestion statique/dynamique (pour s’adapter à la charge du serveur), limites mini/maxi de processus actifs/en attente, type d’écoute par socket Unix ou TCP/IP (pour déporter l’exécution sur un serveur distinct), nombre maxi de requêtes par processus avant extinction. Le redémarrage complet du pool est également supporté en cas de crash suite à une fuite mémoire. Le recours à un outil équivalent mais limité en option, tel que spawn-fcgi n’est donc plus nécessaire (référez-vous à mes articles à son sujet : ici et ici). J’oubliais l’utilisation d’un cache de code PHP tel que APC ou Xcache est possible vu que les processus php-fpm ne sont pas détruits après chaque requête.

Je vous fais part des étapes nécessaires à sa mise en place, effectuées ici sous FreeBSD 8.1 & Nginx.

  • Configuration de PHP

Il faut s’assurer d’activer le flag de compilation de PHP-FPM :

# cd /usr/ports/lang/php5
# make config
# make install

On oublie pas l’extension de sécurité suhosin et le cache APC :

# cd /usr/ports/security/php-suhosin
# make install
# cd /usr/ports/www/pecl-APC
# make install

Une petite vérification de routine :

# php -v
PHP 5.3.3 with Suhosin-Patch (cli) (built: Aug  9 2010 21:34:21)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
 with Suhosin v0.9.32.1, Copyright (c) 2007-2010, by SektionEins GmbH
  • Configuration de PHP-FPM

Le module dispose de son propre fichier de configuration /usr/local/etc/php-fpm.conf :

[global]
pid = /var/run/php-fpm.pid
;error_log = /var/log/php-fpm.log
[www]
# socket
listen = /tmp/php-fpm.sock
listen.owner = www
listen.group = www
listen.mode = 0666
# user ID/GID
user = www
group = www
# pool
pm = dynamic
pm.max_children = 20
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 8

Est configuré un pool de processus dynamique avec un maximum de 20 processus PHP, avec écoute par socket UNIX, le tout limité au compte utilisateur du serveur web www. Le démon peut à présent être lancé :

# echo "php_fpm_enable="YES" >> /etc/rc.conf
# /usr/local/etc/rc.d/php-fpm start
Starting php_fpm.

Le pool PHP devrait être en exécution :

# su -m www
www# ps aux|grep php
www  68220  0.6  2.3 110152 48216  ??  SJ   11:56PM   0:00.95 /usr/local/sbin/php-fpm
www  68219  0.0  0.6 99912 12540  ??  IJ   11:56PM   0:00.00 /usr/local/sbin/php-fpm
www  68221  0.0  0.6 99912 12540  ??  IJ   11:56PM   0:00.00 /usr/local/sbin/php-fpm
www  68222  0.0  0.6 99912 12540  ??  IJ   11:56PM   0:00.00 /usr/local/sbin/php-fpm
www  68223  0.0  0.6 99912 12540  ??  IJ   11:56PM   0:00.00 /usr/local/sbin/php-fpm
www  68224  0.0  0.6 99912 12540  ??  IJ   11:56PM   0:00.00 /usr/local/sbin/php-fpm
www  68225  0.0  0.6 99912 12540  ??  IJ   11:56PM   0:00.00 /usr/local/sbin/php-fpm
www  68226  0.0  0.6 99912 12540  ??  IJ   11:56PM   0:00.00 /usr/local/sbin/php-fpm
www  68402  0.0  0.1  9092  1172   1  R+J  12:00AM   0:00.00 grep php
  • Configuration de Nginx

Le module FastCGI doit être configuré pour utiliser le pool. J’utilise pour ce faire un fragment de configuration que j’inclue dans chaque vhost où PHP est nécessaire :

# cd /usr/local/etc/nginx/
# more fragments/php.conf
fastcgi_pass   unix:/tmp/php-fpm.sock;
fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME    $request_filename;
include        fastcgi_params;

Le nom et le type de socket doit correspondre ici à ce qui a été déclaré dans la configuration de PHP-FPM.

# more vhosts/site_fr.conf
server {
 listen 172.16.0.5:80;
 server_name www.site.fr;
 root /usr/local/www/site.fr/www/html;
 index index.php;

 location ~ \.php$ {
  include fragments/php.conf;
 }
}

Nginx peut enfin être redémarré  :

# /usr/local/etc/rc.d/nginx restart
Performing sanity check on nginx configuration:
the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
configuration file /usr/local/etc/nginx/nginx.conf test is successful
Stopping nginx.
Waiting for PIDS: 89603.
Performing sanity check on nginx configuration:
the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.

L’exécution des scripts PHP est à présent assurée par le pool PHP-FPM.

Apache : désactiver le support SSLv2

<VirtualHost 172.16.0.14:443>
   ServerName www.site.fr
   DocumentRoot /home/www/sites/site.fr/www/html
   ErrorLog /home/www/sites/site.fr/www/logs/error_log
   Customlog /home/www/sites/site.fr/www/logs/access_log combined

   SSLEngine on
   SSLProtocol -all +SSLv3 +TLSv1
   SSLCipherSuite ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM
   SSLCertificateFile /etc/apache2/ssl/www_site_fr.crt
   SSLCertificateKeyFile /etc/apache2/ssl/www_site_fr.key
</VirtualHost>

Nginx : désactiver le support SSLv2

server {
   listen       172.16.0.15:443;
   server_name  mon.site.fr;
   root         /usr/local/www/mon.site.fr;
   index        index.php;

   ssl                  on;
   ssl_certificate      ssl/mon_site_fr.crt;
   ssl_certificate_key  ssl/mon_site_fr.key;
   ssl_session_timeout  5m;
   ssl_protocols SSLv3 TLSv1;
   ssl_ciphers HIGH:!ADH:!MD5;
   ssl_prefer_server_ciphers   on;
}

Apache : activer la compression gzip

Après avoir compilé et activé le module mod_deflate d’Apache, la directive suivante est à ajouter au virtual host :

<IfModule mod_deflate.c>
   SetOutputFilter DEFLATE

   # disable compression for broken browsers
   BrowserMatch ^Mozilla/4 gzip-only-text/html
   BrowserMatch ^Mozilla/4\.0[678] no-gzip
   BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
   BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

   # disable compression for images
   SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
   # disable compression for other files
   SetEnvIfNoCase Request_URI \.(?:pdf|htc)$ no-gzip dont-vary
   # disable compression for binaries and archives
   SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
   # proxy cache support
   Header append Vary User-Agent env=!dont-vary

   # deflate log support
   #DeflateFilterNote Input instream
   #DeflateFilterNote Output outstream
   #DeflateFilterNote Ratio ratio
   #LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' deflate
   #Customlog /var/log/apache2/deflate_log deflate
</IfModule>

Cherokee : le serveur web qui réconcilie administrateurs et développeurs

Un serveur web rapide, léger et facilement configurable ? C’est Cherokee !

Toutes les fonctions sont présentes : TLS, FastCGI, rewrite, proxy, cache, journalisation Apache, expiration, compression, limitation du trafic … et en plus une interface web de configuration dont la simplicité est déconcertante. Cette dernière prouve son réel intérêt avec le mécanisme des règles appliquées au contenu. Des assistants sont même présents pour configurer automatiquement le support PHP, créer un hôte pour WordPress, Mailman, etc …

Niveau performances, un benchmark prouve sa supériorité face à Nginx / Lighttpd (sans compter l’autre que je ne nommerai pas), mais il manque un test avec 100/200 clients simultanés pour être certain que les performances ne s’effondre pas à forte charge (ce qui est toujours le cas, OS oblige). L’interface de configuration fonctionne dans un processus séparé, son exécution est donc indépendante et peut être arrétée à tout moment.

Voici quelques screenshots de l’interface web :

PS : non, je n’ai pas acheté le dernier Linux Mag.

Apache : empêcher l’interprétation des fichiers à extensions multiples

Pour éviter l’interprétation des fichiers à extensions multiples (par ex monimage.pl.gif) en tant que script, il est possible de forcer l’option AddHandler d’Apache à ne vérifier que la dernière extension, comme ceci :

AddHandler x-suphp-cgi   .cgi$ .pl$

La documentation ne le précise pas, mais l’extension semble bien être une regex. Ainsi le fichier monimage.pl.gif ne sera plus executé en tant que script Perl, mais affiché comme il se doit en image GIF.

Dans le cas où l’usage n’est valable que pour un seul vhost, il vaut peut être mieux se rabattre sur cette solution : http://httpd.apache.org/docs/2.2/mod/mod_mime.html#multipleext

Haut de page