mercredi 23 septembre 2015

socat … so cute!

Avec la puissance de calcul désormais disponible, et depuis peu sur notre poignet, l'accès Internet à haut débit, il m'est difficile d'être patient lorsque, naviguant sur un site lambda, un petit chenillard, ou tout autre forme d'animation, me fait comprendre que ma demande est en cours de traitement et que ..., bien des instants plus tard, rien ne se passe.

Alors j'enrage, "Il fait quoi le serveur? ... Bon il va répondre, ça commence à bien faire ! ... S'il te plait, réponds, et j'arrête de t'embêter après ... Je peux rien faire, je me sens tout seul ! ... OK, c'est décidé, j'achète chez le concurrent!".

Mais au fait, je fait comment déjà sur les applications que je développe ? Eh oui, facile pour moi de voir la paille dans l'œil du voisin, mais que faire alors de la poutre que j'ai dans le mien ?

Voici dans un premier temps de quoi extraire une écharde : un petit banc de test permettant de simuler un ralentissement au sein d'une infrastructure.

1. Observons le phénomène

Prenons au hasard le cas d'un simple Blog: une base de données s'occupe de stocker précieusement le contenu des pages, le détail des comptes utilisateurs, les droits d'accès ... Un serveur Web interroge la base de données pour effectuer le rendu des pages, ces dernières étant affichées dans le butineur Internet du lecteur/de la lectrice. Entre ces 3 éléments se situe un intermédiaire : le réseau. Le serveur Web effectue donc une connexion réseau, envoie des données dans le tuyau et attend la réponse de l'interlocuteur. Pour mille et une raisons cette réponse peu tarder à venir et peut-être même ne jamais aboutir. Le serveur ne répond donc pas, le butineur n'affiche donc rien à l'utilisateur qui enrage, jette son ordinateur par la fenêtre et fini par aller élever des chèvres dans le Périgord.

2. Traitons le phénomène

Il convient donc de maîtriser le temps que prennent les échanges et empêcher qu'ils ne durent trop longtemps. En supposant que ce soit facile, il est temps de prendre une décision : que fait-on à l'expiration du délais maximum de l'échange ? J'aimerai qu'une réponse simple à cette question existe, mais hélas, c'est une affaire de contexte et il faudra y réfléchir au cas par cas.

En reprenant mon exemple, où aucune vie n'est en jeu et où il n'y a aucune conséquence financière en vue, je choisis de faire planter le serveur. Car comme le dit un vieil adage : “Programme qui meurt ne ment jamais!“ (source inconnue).

Notre serveur nouvelle version effectue le même échange que précédemment avec la base de données, à ceci près que cette fois, une barrière temporelle limite les échanges à quelques secondes, après quoi une exception brise le traitement et renvoie à l'utilisateur une page d'erreur. Ce dernier prend ainsi conscience de la peine qu'éprouve se petit programme à ne pas pouvoir faire son travail dans les meilleures conditions et va plutôt prendre l'air quelques instants avant de retenter sa chance quelques instants plus tard.

3. Observons la rémission

Comme indiqué plus haut, le ralentissement des échanges entre le serveur et la base de données est un symptôme commun à de multiples maladies : disque dur à l'article de la mort, réseau très encombré, moteur de basse de données soumis à une très forte charge ... alors comment être sûr de notre correction face à ces problèmes sensés ne jamais se produire ?

Dans le cas de systèmes communiquant au travers d'une socket TCP, une astuce consiste à introduire un intermédiaire entre les 2 extrémités, et d'agir sur cet intermédiaire pour ralentir et/ou interrompre la communication avec une contrainte majeure : ne pas intervenir sur les systèmes afin qu'ils se comportent de manière identique à l'accoutumée.

Cet intermédiaire existe sous *nix sous le nom de socat. Ainsi notre serveur Web sera configuré pour se connecter à socat tandis que ce dernier sera configuré pour relayer les échanges avec le vrai serveur de base de données.

$ socat TCP4-LISTEN:1234,fork,reuseaddr TCP4:mon.server.gbd:1234

Autre magie d'unix, un simple CTRL + Z pendant l'execution de socat le mettra en stase, simulant ainsi une absence ponctuelle de réponse.

À noter que $ kill -SIGSTOP <pid> et $ kill -SIGCONT <pid> peuvent être utilisés de la même manière pour suspendre / relancer un process.

Victoire!

Nous avons dissocié le temps d'exécution du serveur Web et celui du serveur de base de données. Nous avons fait des choix concernant le comportement approprié en cas d'une panne et plus que tout, nous avons pu tester les effets en simulant in vitro.

On peut trouver un peut trop simpliste le cas d'usage cité, mais imaginons les conséquences d'une lenteur ou d'une non réponse dans des systèmes multi tiers: c'est domino day. Comme très bien expliqué dans ce livre qui va bien au delà du seul temps de réponse.

Et vous ? Dans quel mesure la vie opérationnelle de vos applications vous préoccupe-t-elle ? Les temps de réponses vous concerne-t-il ? Quelles lessons tirez-vous de votre pire expérience ?