Problèmes de lenteurs serveur ? Load average énorme !

Ce matin, j’ai été confronté à des problèmes de lenteur serveur. Des temps de réponses excessivement hauts, d’énormes latences en SSH, un load average énorme.

Quel a été la démarche pour résoudre ce problème ? C’est l’objectif de ce billet de présenter les problèmes rencontrés.

Tout d’abord, il faut savoir que j’ai mis en place un script de surveillance de la charge serveur. Celui-ci, qui tourne sur un cron, me prévient lorsque le load average dépasse 1.
J’ai volontairement mis la valeur assez basse, pour anticiper au mieux tout problème.

Si vous voulez en apprendre un peu plus sur ce qu’est le load average, je vous recommande cet article.

Le script que j’utilise est le suivant :

max_loadavg=1

date=`date '+%d-%m-%Y'`
loadavg=$(cat /proc/loadavg | awk '{print $1}')

if [ $(echo "$loadavg >= $max_loadavg"|bc) -eq 1 ]
then

SUBJECT="`hostname` ALERT LOAD AVERAGE $loadavg(>$max_loadavg)"
EMAIL="xxxxxxxxxxxx@xxxxxxx.xx"
EMAILMESSAGE="Load Average : $loadavg on `date`"

echo $EMAILMESSAGE | mail -s "$SUBJECT" "$EMAIL"

fi

exit

Ce matin donc, je reçoit un mail pour me prévenir que la charge est trop importante. En effet, le message est le suivant
Load Average : 29.28 on dimanche 20 mars 2011, 07:08:01 (UTC+0100)

Je lance mon putty, et j’execute la commande suivante :

root@r00000:~$ uptime
07:15:59 up  7:06,  2 users,  load average: 26.09, 29.07, 31.01

Le problème est bien toujours présent. Je commence ma recherche :

top -b -n 1 | awk '{if (NR <=7) print; else if ($8 == "D") {print; count++} } END {print "Total status D: "count}'

Cette commande trouvée sur le net me permet d’obtenir une liste de processus source du problème.

Et là bingo, j’ai une liste considérable de processus cron dans ma liste : le problème vient de là, il ne me reste plus qu’à vérifier et à résoudre.

Je prend mon mal en patience, le temps d’ouvrir l’édition de crontab, je commente toutes les lignes, et je relance.
Plus de problème, la charge se remet à baisser, le soucis provient bien de là. Il ne me reste plus qu’à fouiner un peu les executions du cron pour trouver le problème et le corriger.

crontab se relance… et pour l’instant, je touche du bois !

Publicités

Mettre en place un placeholder et son failback

Le HTML5 apporte un nouvel attribut aux champs input text et assimilés : placeholder.

Le principe de cet attribut est simple : lorsqu’un champ est vide, on affiche un texte de remplacement pour indiquer ce que doit contenir le champ. Il est très utilisé au niveau applicatif, comme dans l’omnibar de Firefox par exemple :

Placeholder de l'omnibar de Firefox

Le HTML5 nous permet de l’utiliser nativement. Cependant, cet attribut n’est pas encore disponible sous tout les navigateurs. L’objectif fixé par cet article est de mettre en place le système ainsi qu’un bon failback.

Pour effectuer tout ceci, j’utiliserais jQuery. Le script peut bien entendu être étendu à tout les framework, et je vous invite à mettre en commentaire le système avec d’autres systèmes.

Si l’on veut faire simple et tout gérer en JavaScript, il suffit d’écrire un code tel que le suivant :

$('input[type="text"]').blur(function() {
	if (this.value == '') {
		this.value = this.defaultValue;
	}
}).focus(function() {
	if (this.value == this.defaultValue) {
		this.value = '';
	}
})

Ce modèle présente une limitation, mais nous verons ça plus tard.

Le premier point à mettre en place est la reconnaissance de la présence du placeholder. On va ici utiliser la même méthode que Modernizr :

var input = document.createElement('input');
if (!('placeholder' in input)) {
	// Faire ici le traitement pour les navigateurs ne reconnaissant pas le placeholder
	// Il suffit d'y placer le code précédent par exemple !
} else {
	// On supporte le placeholder : on vide la valeur par défaut
	$('input[type="text"]').val('');
}

Et voilà, le système est en place et il suffit de mettre en application le placeholder sur le champ input :


Aller plus loin :

Les plus perspicaces vont tout de suite remarquer la limitation de cette méthode : Obligation de vider la valeur du champ de formulaire, dont pas de valeur par défaut possible, Impossible de rentrer le même texte que le placeholder, …

On peut aussi parler du l’interdiction du JavaScript, mais je considèrerais cela comme un détail sans importance : les plus grands sites (gmail, facebook, …) obligeant à l’utiliser, j’ommetrais les visteurs récalcitrants.

Les problèmes exposés, attaquons la première amélioration :

Afin d’éviter les problèmes de valeurs par défaut, je vais utiliser la trop peu connue fonction de jQuery data.

$('input[type="text"]').each(function () {
	var $this = $(this);
	var $default = $this.data('placeholder');
	if ($default === undefined) {
		return;
	}
	$this.data('placeholderactive', true);
	$this.focus(function () {
		if ($this.data('placeholderactive') === true && $this.val() == $default) {
			$this.val('').removeClass('placeholderactive').addClass('placeholderinactive');
			$this.data('placeholderactive', false);
		}
	}).blur(function () {
		if ($this.data('placeholderactive') === false && $this.val() == '') {
			$this.val($default).removeClass('placeholderinactive').addClass('placeholderactive');
			$this.data('placeholderactive', true);
		}
	}).val($default).removeClass('placeholderinactive').addClass('placeholderactive');
});

Et son nouveau champ input associé :


Pour mettre un style différent sur le champ placeholder, j’ai utilisé deux classes : placeholderactive et placeholderinactive qui s’occupent respectivement d’avoir un style en mode « placeholder » et un style hors de ce mode.

A vous de jouer et d’implémenter ce nouvel attribut HTML5 sur vos site !

N’hésitez pas à partager vos méthodes pour les autres framework JS ou les améliorations à apporter à mon script jQuery.

Laissez votre iPhone choisir pour vous

Il m’a souvent été utile d’avoir un script pour tirer aléatoirement une valeur parmi plusieurs.
Le pile ou face étant limité à 2 choix, et comme je n’ai pas toujours de dés sur moi, j’ai décidé de développer une application pour mon iPhone, qui me permettrais de faire les choix à ma place.

Le fonctionnement est simple : Il suffit de rentrer les valeurs désirées, puis de cliquer sur le header « Random it! » pour voir apparaitre le résultat.

A quoi ressemble l’application :

Pour se rendre sur l’application, il suffit de naviger à l’adresse suivante depuis le smartphone : http://tools.brunosabot.com/random

La théorie veut que le fonctionnement soit le même sous un autre OS mobile comme Android, mais ce n’est pas testé.

Quick Tip – Les « includes » et les « require » de PHP

Avez-vous déjà utilisé les includes et les require de PHP ?

Si oui, vous êtes peut-être déjà tombés sur le problème suivant : lorsque l’on utilise un include, le caractère « null » coupe l’inclusion du fichier.

Avez-vous déjà utilisé les includes et les require de PHP ?

Si oui, vous êtes peut-être déjà tombés sur le problème suivant : lorsque l’on utilise un include, le caractère « null » coupe l’inclusion du fichier.

Le problème est principalement posé lors de l’inclusion dynamique d’un fichier. Imaginez un simple sur le site example.com :


Il suffit d’utiliser l’URL http://example.com/?file=.htaccess%00 pour accéder au contenu du fichier .htaccess, et éventuellement bien pire !

Pour résoudre le problème ? Vérifier que le fichier inclus est bien un fichier que l’on autorise à l’inclusion, avec éventuellement un tableau des fichiers autorisés, tester que le fichier est bien un fichier PHP (et donc que le contenu sera interprété), et toute autre vérification, qui bien entendu ne sera pas superflue.

Mais évidement, vous faites déjà les vérifications nécessaires 😉

Statsy v2 – Quelques ajouts

Stoyan Stefanov à présenté Stasty, un bookmarklet qui permet d’obtenir très rapidement des informations notamment sur les style et script présents en inline sur une page.
Cependant, il manque sur ce script quelques informations importantes, facilement récupérables.
J’ai donc créé un nouveau bookmarklet avec des infomations un peu plus complètes.

Stoyan Stefanov à présenté Stasty, un bookmarklet qui permet d’obtenir très rapidement des informations notamment sur les style et script présents en inline sur une page.

Cependant, il manque sur ce script quelques informations importantes, facilement récupérables.

J’ai donc créé un nouveau bookmarklet avec des infomations un peu plus complètes :

Statsy 2
(function(){
    var jsattribs = [
        'onbeforeunload',
        'onclick',
        'ondblclick',
        'onerror'
        'onload',
        'onmousedown',
        'onmousemove',
        'onmouseout',
        'onmouseover',
        'onmouseup',
        'onunload',
    ],
    cssattribs = [
        'style'
    ];

    var all_elems = document.getElementsByTagName('*');

    function getAttribsSize(attribs) {
        var value = '',
            attr = '',
            cnt = 0;

        for (var i = 0; i < all_elems.length; i++) {
            for (var j = 0; j < attribs.length; j++) {
                attr = attribs[j];
                value = all_elems[i].getAttribute(attr);
                if (value && typeof value === 'string') {
                    cnt += attr.length;
                    cnt += 3; // ="..."
                    cnt += value.length;
                }
            }
        }
        return cnt;
    }

    function getInlineSize(tag) {
        var s = 0,
            all = document.getElementsByTagName(tag);
        for (var i = 0; i < all.length; i++) {
            s += all[i].innerHTML.length;
        }
        return s;
    }

    var jsatt = getAttribsSize(jsattribs);
    var cssatt = getAttribsSize(cssattribs);

    var msg = [];
    msg.push('JS in HTML attributes: '+jsatt+' bytes');
    msg.push('CSS in HTML attributes: '+cssatt+' bytes');
    msg.push('JS in SCRIPT tag: '+getInlineSize('script')+' bytes');
    msg.push('CSS in STYLE tag: '+getInlineSize('style')+' bytes');
    msg.push('All innerHTML: '+document.documentElement.innerHTML.length+' bytes');
    msg.push('# SCRIPT tag: '+document.getElementsByTagName('script').length);
    msg.push('# STYLE tag: '+document.getElementsByTagName('style').length);
    msg.push('# DOM elements: '+all_elems.length);
    msg.push('Cookie size: '+document.cookie.length+' bytes');

    alert(msg.join("n"));
})();

Vous pouvez directement récupérer le bookmarklet ici :

Statsy 2

N’hésitez pas à faire vos suggestions !

UPDATE 30/11/2010

Suite à la demande de jpvincent, petit explicatif des différentes informations remontées :

JS in HTML attributes : Cette information remonte tout le code JavaScript présent directement dans les balises HTML en tant qu’attribut. Par exemple, une page qui contiendrait <h1 onmouseover= »alert(‘H1’); »></h1> ajouterait 26 bits à JS in HTML attributes

CSS in HTML attributes : Même procédé que pour les JavaScript détaillés un peu plus haut, en utilisant cette fois le contenu des attributs style (ex. style= »color:#f00; »)

JS in SCRIPT tag : Cette information remonte le nombre de bits du code JavaScript présent au sein de balises

JCSS in STYLE tag : Même principe que la propriété précédente, cette information remonte le nombre de bits du code CSS présent au sein de balises <style></style>

# SCRIPT tag : Compte le nombre d’occurrence d’utilisation des balises <script> au sein de la page

# STYLE tag : Compte le nombre d’occurrence d’utilisation des balises <style> au sein de la page

# DOM elements : Compte le nombre d’éléments DOM au sein de la page

Cookie size : Retourne la taille en bit des cookies présent sur le fichier HTML, et donc probablement sur tout les fichiers statiques s’ils ne sont pas sur un domaine externe

Décompression de fichiers sous Linux

Les formats de décompressions sous Linux sont assez compliqués à retenir, surtout étant donné le nombre de formats de compression existants.

Dans un de ses tweets, @zeroload pose ce problème.
J’utilise personnellement un script pour effectuer le travail. Celui-ci, récupéré il y a longtemps sur Internet et ajusté à mes besoins, il choisi son mode de décompression en fonction des formats du fichier, et exécute la commande associée.

Pour l’utiliser, il suffit de placer les lignes suivantes dans le fichier .bashrc :

extract () {
	if [ -f $1 ] ; then
		case $1 in
			*.7z) 7z x $1 ;;
			*.bz2) bunzip2 $1 ;;
			*.gz) gunzip $1 ;;
			*.rar) rar x $1 ;;
			*.tar) tar xvf $1 ;;
			*.tar.bz2) tar xvjf $1 ;;
			*.tar.gz) tar xvzf $1 ;;
			*.tbz2) tar xvjf $1 ;;
			*.tgz) tar xvzf $1 ;;
			*.Z) uncompress $1 ;;
			*.zip) unzip $1 ;;
			*) echo "Le format de compression de '$1' n'est pas supporté..." ;;
		esac
	else
		echo "'$1' n'est pas un fichier !"
	fi
}

On peut bien entendu ajouter très facilement un nouveau format géré par le script, et pourquoi pas créer une autre fonction pour gérer la compression suivant plusieurs formats !

NB: Pour recharger le fichier .bashrc, il suffit de se reconnecter au compte, ou de faire :

cd
. .bashrc

Inauguration

Non mis à jour depuis trop longtemps, mon ancien blog était devenu obsolète.

Le web évolue très vite et deux ans sont, à l’échelle du web, une éternité.

Avant de commencer les différents posts, petit récapitulatif de ce que va être ce blog.

Je suis salarié depuis presque 10 mois chez GLOBALIS media system.

Au sein de cette société, j’occupe en premier lieu le post de développeur, mais aussi celui de technicien Front-end.

Ces deux activités m’amènent donc à présenter ici tant la partie optimisation front-end des sites que différentes astuces de codage sur les technologies PHP, MySQL, JavaScript, HTML, CSS ou encore dans l’administration des serveurs.

Pour ce blog, j’ai choisi la plateforme WordPress. Je suis preneur de tout conseil sur différents plugins que vous pourriez me recommander.

Certains billets seront copiés de l’ancien blog ici, il est donc normal de voir apparaitre certains billets avant celui-ci.