L’infrastructure VDM : Memcache

Par Maxime, le 17 mars 2010.

La semaine dernière, je vous annonçais la création d’une suite d’articles concernant l’infrastructure de VDM. J’ai commencé en présentant mes serveurs MySQL. Récapitulatif :

betacie_network.png
L’infrastructure que j’ai montée pour VDM/FML

Dans cette série de billets (normalement trois en comptant celui là), je vais vous raconter ce qui se passe derrière les URL viedemerde.fr et fmylife.com, qui représentent 98% du trafic de l’infrastructure d’hébergement de ma société, Beta&Cie. Ces articles n’ont pas pour vocation de me vanter ou de dire au monde entier que ma solution est la meilleure, c’est juste ma solution et elle marche bien jusqu’à maintenant.

Aujourd’hui, parlons de Memcache.

Présentation de memcached

Comme nous l’avons vu la semaine dernière, les serveurs de données sont bien remplis en données diverses et variées, que ce soit des votes, des anecdotes, les informations de connexion. Beaucoup de données, dont une partie est redondante. Mais pas la totalité de la page puisque chaque anecdote est votée, impossible donc de cacher toute la page.

Un serveur memcached (d pour daemon) est un serveur léger qui permet de stocker temporairement des données en RAM. Si léger qu’il ne dispose d’aucun système d’identification pour accéder ou modifier ces données, donc faites bien attention à ne faire écouter le serveur qu’en local si vous installez un jour une telle solution pour votre serveur.

Son utilisation sur VDM

La technologie memcached permet donc de stocker n’importe quel type de données. Il sert souvent par exemple sur des clusters de serveurs Web pour centraliser les sessions PHP. On peut donc facilement en tirer profit pour mettre en cache plusieurs informations du site, et ainsi soulager de manière significative les serveurs MySQL.

memcache.png
One server to rule them all.

La problématique est maintenant la mise en place de cette solution sur le code PHP existant de VDM. PHP possède une extension Memcache qui permet d’implémenter facilement une solution de cache.

La solution que j’ai retenue est résumée dans le code suivant. Les requêtes SQL sont transformées en hash MD5 pour le nom de la clé, et l’objet du résultat de la requête est stockée en cache, avec un cache par défaut d’une heure (3600 secondes). De cette manière, si la clé n’existe pas sur le serveur memcached, la requête est automatiquement exécutée et le résultat stocké.

<?php

$memcache = new Memcache();
$memcache->pconnect("127.0.0.1","9000");

function mcache($query,$timeout=3600,$force=false) {

	global $memcache;

	$hash = md5($query);

	if (!$force) {

		$value = $memcache->get($hash);

	}

	if ($force || $value === FALSE) {

		$result = mysql_query($query);
		$value = mysql_fetch_object($result);
		$memcache->set($hash,$value,NULL,$timeout);

	}

	return $value;

}

function mcache_set($query,$value,$timeout=3600) {

	global $memcache;

	$hash = md5($query);

	$value = $memcache->set($hash,$value,NULL,$timeout);

	return $value;

}

function mcache_delete($query) {

	global $memcache;

	$hash = md5($query);
	$value = $memcache->delete($hash);

	return $value;

}

?>

Grâce à ces fonctions nous avons conservé toutes nos requêtes, et pouvons utiliser de manière transparente soit Memcache soit MySQL. Plus pratique pour pouvoir synchroniser rapidement les données entre les deux serveurs, en plus d’avoir facilité la migration vers Memcache.

Exemple d’utilisation :

<?php

/* Je suis un nul alors je mets pas de mot de passe en root */
mysql_connect("localhost","root","");
mysql_select_db("base");

/* La requête MySQL normale sans cache */
$result = mysql_query("SELECT texte FROM articles WHERE id = '1337' LIMIT 1");
$row = mysql_fetch_object($result);

/* La requête avec le cache Memcache */
$row = mcache("SELECT texte FROM articles WHERE id = '1337' LIMIT 1");

?>

Grâce aux fonctions mcache() et consorts, on peut donc sans trop de difficultés alléger le travail des serveurs de bases de données. Si vous avez besoin de mettre en cache un tableau de résultats, vous pouvez utiliser la fonction suivante :

<?php

function mcache_array($query,$timeout=3600,$force=false) {

	global $memcache;

	$hash = md5($query);

	if (!$force) {

		$value = $memcache->get($hash);

	}

	if ($force || $value === FALSE) {

		$memcache->delete($hash);

		$result = mysql_query($query);
		while ($row = mysql_fetch_object($result)) {
			$value[] = $row;
		}

		$memcache->set($hash,$value,NULL,$timeout);

	}

	if (!is_array($value)) $value = array();
	return $value;

}

?>

Ainsi, sur VDM et FML, nous mettons en cache principalement les données suivantes :

  • Les données « statiques » des anecdotes (texte, auteur, etc.)
  • Les totaux des votes sur les anecdotes (mis à jour à chaque vote sans appel à MySQL)
  • Les ID des dernières anecdotes lues par les utilisateurs, pour afficher les « NEW »
  • Certains rendus XML de l’API pour les applications mobiles

Au niveau des chiffres, voici des statistiques sur les 3 dernières semaines d’utilisation du serveur memcached :

  • 900 connexions simultanées en permanence
  • 90 000 connexions par jour
  • 14,4 Mo écrits par seconde (via 622 requêtes en moyenne)
  • 1,8 Go de données stockées en ce moment
  • 6,9 millions de données stockées en ce moment
  • 1,3 milliard de données stockées en tout

Comme d’habitude, n’hésitez pas à commenter pour plus d’informations, j’ai sûrement oublié beaucoup de choses. La semaine prochaine nous parlerons de serveurs Web.

75 commentaires

Palleas

Intéressant, ya juste le global qui m’a donné envie de te lancer des petits cailloux :)

Clément

Question : Comment fait tu pour mettre a jour les votes sans accès a MySQL ? Tu le stock dans même cache et tu balance une requete toutes les 3600 secondes ?

Merci en tout cas ;) c’est excellent ^

Farof

Des chiffres, on veux des chiffres ! :p
Ça représente quoi en terme de get / set par secondes, et ça demande quel volume de RAM ?

Aweb

Bonjour,

Très bon exemple d’utilisation de memcache auquel je n’avais pas pensé, bravo :)

Cependant, as-tu pensé aux possibilités de collisions md5 (deux requêtes différentes peuvent avoir le même md5), que fais-tu pour les éviter ?

Merci pour ce blog ;)

Maxime —

J’ai rajouté des chiffres, désolé :)

@Clément : C’est mis à jour via les valeurs stockées dans le cache oui, c’est synchronisé par MySQL environ toutes les heures pour être sûr !

@Aweb : Les collisions md5 étant extrêmement rares (et encore c’est un euphémisme), je n’ai pas songé à les éviter, non.

Raphaël

Ca paraît tellement simple vu comme ça ;-) Merci pour l’article !

flob9 —

Article intéressant.
Concernant les requêtes, j’ai déjà fait pareil (utiliser le md5 comme clef), mais au final pour purger c’est vraiment pas pratique. Dans ton exemple j’aurais plutôt utilisé comme clef memcache un truc du genre : « texte-article-1337″
de façon à pouvoir faire simplement un $memcache->replace si le texte est modifié dans la bdd. Parce que là, va retrouver le md5 de ton select au moment ou tu fais un update sql …

Dernier petit truc (précision en fait) après j’arrête de faire chier, on peut utiliser addserver au lieu de connect/pconnect, ça permet d’avoir plusieurs serveurs memcache en load balancing.

Maxime

@Flob9 : Pas besoin de retrouver le hash puisqu’il est calculé. Si tu sais l’id tu sais la requête. Et ça permet de garder la retrocompatibilité.

Sinon oui pour le addserver mais je n’en ai qu’un :) et ça suffit largement.

flob9 —

J’ai du mal expliquer ce que je voulais dire. Imaginons que sur une page tu aies ceci :
$row = mcache(« SELECT texte FROM articles WHERE id = ’1337′ LIMIT 1″);

et, autre part dans le code :
mysql_query(« UPDATE articles SET texte = ‘blabla’ WHERE id = 1337″);

Après cet update, pour avoir la bonne valeur dans memcache, il te faut la requête exacte et faire :
mcache_delete(« SELECT texte FROM articles WHERE id = ’1337′ LIMIT 1″);

Pas top, car si tu modifie ton select d’un seul caractère d’un coté et pas de l’autre, ça ne marche plus. Alors que si tu mets une autre clef que le md5 de la requête, tu peux facilement faire un $memcache->delete(‘texte-article-1337′) après l’update.
Je t’accorde quand même que la méthode du md5 est pratique – quand tu n’as pas besoin de faire des delete/update.

avrelus

Bonjour,
ma question concerne le matériel utilisé pour le(s) serveur(s) memcached. Sans entrer dans trop de détails si ce sont des informations sensibles, pouvez-vous m’expliquer quel type de serveur vous utilisez ?
RAM, processeur, prix etc
Merci

bohwaz

Donc dans ton schéma normalement le memcache est entre les fronts et les sql ?

Mat —

Pas mal le système des hash de requête ! =)
@Palleas : moi c’est plutôt les test sur les booléens qui m’ont fait tiquer :p (genre $force == true)

flob9 —

J’osais pas le dire :D
Pareil pour le test sur $value dans mcache_array alors qu’il n’est pas initialisé si $force est à false… ou alors le $memcache->get qui sert à rien quand $force est à true dans la fonction mcache.

Ca fait un peu code d’étudiant tout ça, mais j’ose espérer que c’est pas du code en prod, juste de la demo, et que personne va le copier/coller pour l’utiliser sans le corriger au préalable.

John —

Bonne question, c’est du code en production ? Driver mysql procédural, mon préféré (L) pas pdo ? Pour mysql_fetch_object il est préférable d’avoir un mysql_fetch_assoc, les tableaux sont plus rapides à sérialiser que les objets.
Et niveau organisation, tu as une page « fonctions_memcache.php » ou un des modèles ?
En attente de la suite :)
Rares sont les articles/tutoriels effectifs concernant memcache, merci.

Darklg

Merci pour ce deuxième article :)

Aweb

Mat => Je ne vois pas le problème (débutant, désolé…) Faut-il utiliser la triple égalité (===) ?

Mat —

@Aweb : Le principe d’un test c’est de renvoyer un booléen. Donc faire un test pour savoir si une variable est égale à true ou false, c’est un test pour rien. Il suffit d’écrire
if($force)
ou si false
if(!$force)

La triple égalité est nécessaire pour le premier test, car j’imagine que ->get($hash) peut renvoyer un 0.

M’enfin bon, je pense pas que Maxime cherche des commentaires sur l’optimisation du code php en soit. On peut toujours trouver en pinaillant des trucs à modifier, mais quand c’est peanuts (bon là les tests booléens c’est quand même pas top), tu privilégie la productivité.

flob9 —

Critiquer epic purin sur ses qualités d’administrateur, et ensuite poster du code de stagiaire bac -4, c’est quand même très fort :)

Maxime

Les gars, je poste des infos sur mon infrastructure, personne m’oblige à le faire.

Si c’est pour m’insulter derrière je vois pas l’intérêt.

Vous me décevez, là.

beuz —

haha, Maxime tu te fais un peu chahuté et tu prends la mouche, c’est assez drôle venant de ta part ! Sinon, article très intéressant.

Maxime

Ce n’est pas du code en production, le code en production a des parties spécifiques qu’il n’était pas utile de préciser ici. J’ai refait donc les scripts pour montrer basiquement le fonctionnement. C’est clair que ça méritait des insultes :)

@avrelus : L’avantage de memcached c’est qu’il peut tourner sur des P4 sans trop de difficultés, le soft en lui-même est très léger et utilise la RAM disponible.

@bohwaz : Non, le memcache est en relation avec les webservers et il est installé sur un front. Ce n’est pas « entre » c’est des relations.

@John : Pas compris la question sur la « page fonctions_memcache.php » mais ça me semble évident que je ne recopie pas les fonctions sur chacune de mes pages, en tout cas.

@Mat : J’ai fait un bench puisque tu pinailles :) Je gagnerais 20 nanosecondes par if () en omettant le == true. Enfin si je n’avais pas de cache objet, ce qui est le cas. Donc ça ne change rien.

@flob9 : Tu as le droit d’avoir des remarques à faire sur mon code, sur ce que tu veux. Mais dénigrer le travail des autres de cette manière est un comportement simplement honteux. Grâce à tes commentaires j’hésite à écrire une suite à cet article.

Darklg

Par contre, pour pinailler aussi de mon côté, je me suis rendu compte que sur certains serveurs MySQL vraiment lents, il était intéressant de ne pas faire de mysql_connect ni de mysql_close si la page n’a aucune requête à faire. Mais avec ta config, ça m’étonnerait qu’il y ait un énorme changement ^^ »

flob9 —

« dénigrer le travail des autres de cette manière est un comportement simplement honteux »
+1

Franchement je préfère un mec qui délègue ce qu’il ne maitrise pas qu’un autre qui se croit bon et sort un chmod 666 au moindre « permission denied ».
Ca sert à rien de faire ta mijaurée comme ça maintenant, il fallait y réfléchir au moment ou toi tu dénigrais le travail des autres.

Palleas

A titre perso, mon coup des petits cailloux était vraiment histoire de pinailler, parce que le centre du billet n’est pas là dessus (et puis je ne suis pas cité dans les réponses, c’est que tu n’as pas du mal le prendre). Entre les gens qui parlent de la philosophie et de la pérennité du web quand tu sors ton URL shortener, et je ne sais plus quels exemples, les dérapages c’est pas nouveau.

Moi je garde le concept de faire des hashs pour récupérer les requêtes, et j’attends la suite avec impatience, t’as été bon jusque là pour dealer avec la critique, tu vas pas priver tes lecteurs d’infos concrètes et vérifiées, ce serait dommage :)

Maxime

@flob9 : Ah ok, en fait t’es là pour la vengeance. Bon alors je n’ai pas besoin de continuer à te répondre :)

Ne vous inquiétez pas il y aura bien une suite ^^

Saru —

Allez les gens. Faites péter votre code que je vous incendie.

et pour les X ns gagnées, j’ose espérer que le moteur php sait que
if($bool)
ou
if ($bool == true)
c’est la même chose. Donc qu’avec un cache d’opcode, qu’il n’y ait aucune différence entre les deux. Même si c’est au dev de faire du code puissant, PHP se veut un langage facile pour tous. Je tiendrai plutôt le moteur responsable que le code lui même, pour du petit pinaillage comme ca.

flob9 —

Vengeance ? Surement pas, je n’ai rien à voir avec les gens que tu as incendié dans tes précédents billets.

@Saru> langage facile certes, mais le dev n’est pas obligé pour autant de coder à l’arrache.
J’imagine un peu ce qui resortirait avec un error_reporting(E_ALL); en haut du code
if ($force || $value === FALSE) <<< $value pas initialisé dans certains cas
$value[] = $row; <<set($hash,$value,NULL,$timeout); <<< idem

3 notices sur une fonction de 20 lignes, ça va que c'est pas en prod (d'ailleurs j'aime bien le concept de faire des bench sur du code de demo soit disant pas en prod)

Julien

Moi, j’aimerais qu’on parle un peu d’aquarelle. On s’en branle de Memcache.

Maxime

@flob9 : Le bench n’était pas sur ce code là, tu as mal compris.

En tout cas j’ai vu que tu cherchais de l’amitié (http://www.discut.fr/profil-167070-flob9.html), bon courage, c’est pas ici que t’en trouveras, sors d’ici ! :)

flob9 —

argumentum ad hominem, tu me deçois :p
(En effet je suis esthéticienne et je cherche l’amitié. Ou alors c’est un compte de test pour du dev, mais c’est pas indiqué sur la fiche)

Saru —

Non, il n’y a pas de notice:
- cas ou force = false:
value est set par le resultat de memcache->get().
- cas ou force = true:
value n’est pas set, mais n’est jamais testé dans le if, puisque c’est un OU. Force = true, donc le test $value==false n’est jamais effectué. Même un débutant en programmation sait ça.

Meme le $value[] = $row ne génère pas de E_NOTICE.

Tu ferais mieux de tester le code avant de dire des conneries.

Julien

Maxime et Saru, venez, on dessine des arbres !

flob9 —

Me souviens que le []= générait un warning si ce n’était pas un array à la base, mais en effet ce n’est plus le cas maintenant, au temps pour moi.
PHP est laxiste, mais initialiser les variables, ce n’est pas interdit.

Saru —

C’est pas interdit. Mais aller faire des init quand c’est pas utile, c’est de la perte de perf.

Alors viens pas hurler a la perf, alors que tu ne sais pas utiliser l’ordre de test des opérateurs de base. KTHX.

flob9 —

Tu confond, je n’ai pas hurlé aux perfs moi. Peut-être sur le get qui servait à rien, mais maxime a corrigé depuis.

Greg —

Sympa l’article. Et aussi l’ambiance ;)

Godefroy (@Skreo)

C’est marrant ces pinailleurs qui n’arrêtent pas avec leurs remarques à la con…
Je suis partisan du beau code, mais quand même, ceux qui parlent de perfs pour un if($force==true), c’est vraiment qu’ils n’ont jamais eu à mettre en place une infrastructure devant supporter une importante charge…
Le plus généralement, les problèmes de tenue de charge se situent au niveau du SGBD, d’où l’importance de l’optimisation de la config du SGBD (MySQL en l’occurrence) et de la mise en place d’un cache efficace.

Merci beaucoup à Maxime qui partage ses astuces.

Le seul truc qui me chiffonne c’est, comme en a parlé Flob9, l’utilisation de hash md5 comme clé pour les résultats des requêtes. Si on a plusieurs requêtes SELECT concernant une même entrée dans une table, comment s’assurer que le cache est bien mis à jour lorsqu’on applique un UPDATE ou un DELETE ?…

Je préfère mettre en cache des données par « module ». Par exemple pour l’affichage d’un tag cloud, je mets en cache le code HTML résultant de la requête. Le cache est directement ré-utilisable, et je sais que quand un tag est ajouté, modifié ou supprimé, il faut supprimer le cache du tag cloud. Cette suppression de cache peut même se faire dans une méthode événement de la classe de gestion des tags.

Ce qui m’intrigue aussi, ce sont les spécifications du serveur Memcached. J’imagine qu’il a beaucoup de ram pour supporter autant de données ?

Maxime

@Skreo : S’assurer un cache est mis à jour c’est quand la principale préoccupation quand on parle de cache, de toute façon :) que ça soit avec un hash, des tags, n’importe quoi. L’objectif d’un bon cache est d’être mis à jour uniquement quand il y en a besoin, donc il faut adapter le code en conséquence et être sûr qu’il sera mis à jour. Mais ce n’est pas grand chose à vérifier. Et au pire il y a le timeout d’une heure.

Quant à la RAM, je le mets à la fin du billet, actuellement j’utilise 1,8 Go de données et c’est à peu près stable. Donc pas besoin d’énormément de RAM même si ça dépend bien sûr de ce que tu mets en cache.

Godefroy (@Skreo)

Ok merci Maxime pour tes réponses :-)

arnaud —

si j’ai bien lu, memcached stocke la plus grosse partie de tes données.
ça ne représente que 1.8Go ?!
pourquoi autant de serveurs SQL dans ce cas ?
même en supposant que tu n’aies qu’un dixième de tes données en cache, ça semble toujours énorme :)

Maxime —

@arnaud : Oui ce sont les données les plus importantes qui sont stockées en cache. Le plus gros des données MySQL sont les votes comme je l’ai expliqué la semaine dernière. Seuls les totaux sont en cache, pas toutes les entrées, donc ça sauve du calcul et aussi 30 Go :)

flob9 —

Je sais pas si t’as testé ce truc : https://launchpad.net/memcached-udfs
Ca semble intéressant, par exemple pour mettre un trigger sur update qui met le cache à jour, etc …

Saru —

Pour ma part, j’évite les triggers sous mysql. C’est encore assez « jeune » (implémenté dans mysql5), et très limité comparé a un roc comme pgsql ou oracle.
J’attendrais plutot MySQL6 pour les triggers, imho.

D’autant que pgsql 9.0 est prévu dans pas longtemps :)

Baptiste —

100 lignes de code, 10x plus de commentaires pour critiquer, normal. Les tests unitaires c’est has-been, je vais me créer un blog et poster mes scripts.

bohwaz

Il y a toujours un truc qui me chagrine en regardant le schéma quand même : autant de machines pour si peu de requêtes et de trafic c’est du pur gâchis. Regardez un peu les chiffres : 850.000 votes par jour, si on met ça sur 12h (oui la nuit ça vote pas beaucoup normalement), ça fait du 19 requêtes / seconde, en passant par un memcache je vois pas pourquoi on aurait besoin de plus d’un serveur SQL pour ça. Alors pourquoi sept serveurs ?! Je ne mentionne même pas les commentaires et les anecdotes qui ne devraient pas être un problème même sans memcache.

Mais le plus gênant à mon sens se situe dans la fameuse réplication circulaire qui est un vrai danger en production : si une des machines tombe, toutes les autres derrière prennent du retard de réplication, vas-y le bordel pour le rattraper ensuite. En circulaire sur 2 machines je comprends bien (c’est ce qu’on a chez Skyrock.com, mais avec plusieurs couples hein), mais sur 7 ça me semble dangereux.

Enfin un dernier problème, dans le billet précédent tu parlais de tables temporaires, mais normalement si les requêtes sont bien foutues et les schémas de table aussi, il ne devrait pas y en avoir…

Je me rends bien compte que le code donné ici n’est qu’un exemple mais je me demande si le problème ne se situe pas au niveau du code en prod qui ne chercher pas à être efficace et se repose sur ton architecture sans chercher à s’améliorer.

Steuf —

@bohwaz je dois avouer que je me pose les même question surtout pour des sites qui sont en matière de développement « Simple ». Aucun traitement complexe et liaisons diverses et variées… J’ai du mal à comprendre ce qui justifie une telle batterie de serveur :/

Julien —

Je trouve l’infrastructure effectivement assez conséquente voir presque démesurée? Combien fait de visiteurs uniques fml et vdm confondus par mois?

Steuf

De mémoire Trends annonce 500 000v/j pour les deux cumulés, avec un pic l’année dernière à la sortie de fml ou les deux cumulés auraient dépassés le million. De mémoire hein.

Michel Poulain —

S’inscrit dans la droite lignée des articles hyper intéressants de http://highscalability.com. Merci Maxime.

Maxime

@Julien @Steuf : Plus de 3 millions de visites par jour, en fait. Comme je l’ai souvent répété, je pourrais tourner avec la moitié des serveurs en moins. Sauf que ce n’est pas du « cloud », je ne peux pas rajouter une machine en 5 secondes. Je suis chez un vrai hébergeur, si je demande une nouvelle machine elle sera disponible en 2 semaines. Admettons que le trafic double demain, avec moitié de machines le site sera down. Ce serait balot de perdre tous nos revenus pour économiser un ou deux milliers d’euros par mois.

Steuf

@maxime Oui comme je disais l’année dernière avec fmylife tu as eu quand même une belle poussée d’audience qui explique en partie la chose. Mais bon après tu as peu de chance de voir ton traffic doubler du jour au lendemain quand même. Tu me diras moi à mon boulo on prépare une architecture pour un projet elle sera au départ complétement surdimensionnée mais qui est nécessaire. Mais bon après tout est une question de coût et de capacité à l’assumer ;)

Julien —

Oki c’est bien ce qui me semblait mais ta justification ce tien, si vous n’êtes pas a 1k ou 2k euros prêt alors pourquoi pas!

ALexandre "bragon" Legrix

Tu exagères un peu sur les délais de livraison :)

Jérôme M.

Très sympa, ça me donne plein d’idées. Merci Maxime.

michel v

Et donc, avec cette méthode « simple », il faut pouvoir calculer tous les queries possibles pour invalider un cache ?

*FACEPALM*

michel v

Je précise : possibles pour chaque identifiant de contenu. Par exemple, il faut savoir que le contenu #1337 fait partie de catégorie #42 et donc qu’il faut invalider le cache de « SELECT contenus WHERE categorie=42″.

Quid des caches de requêtes qui ne sont pas déterminables, comme les requêtes de recherche ?

alexandre

Merci beaucoup pour l’article, je me posais justement ce genre de questions.
Pour mettre à jour le cache, je pensais me baser sur la date de dernière modification de la table concernée.
En gros une fonction qui prendrait la requête et la table concernée en argument.
Par défaut ca lit le cache, sauf si la date de mise à jour de la table est supérieure à la date du cache.
Qu’en pensez-vous ?

Et sinon vis à vis du format du stockage, quels sont les avantages inconvénients de stocker sous forme de fichier ?
Je vois bien un problème de scalabilité pour accéder aux données, mais qu’en est il au niveau des perfs ? mieux ou moins bien qu’un memcached ?

Maxime

@alexandre : Les données de memcached se situant en RAM, leur accès sera forcément plus rapide que des données situées sur un disque mécanique. Pour la mise à jour du cache c’est une solution comme une autre, tout dépend des besoins de chacun, il n’y a pas vraiment de solution universelle, ce serait trop beau :)

Steuf

@alexandre

Pour compléter de que dit Maxime, ta solution n’est viable que s’il n’y a pas beaucoup d’écriture dans ta table car plus tu auras d’écriture et tu mettras de plus en plus souvent ton cache à jour en perdant le principe et l’intérêt de celui-ci. Comme le dit Maxime les stratégies en matières de cache dépendent essentiellement de ton environnement et du contexte dans lequel tu veux le mettre en place.

flob9 —

Bon, après avoir bien critiqué, limite insulté, je me permet de donner ici ma méthode memcache, sans prétention, car c’est maxime le guru :D

Une classe à la con qui gère memcache :
http://flob9.pastebin.com/4d62Y32W

Ensuite, pour l’utilisation :
http://flob9.pastebin.com/YvPN8fip

Voilà; si ca peut aider, tant mieux. Si je me fais insulter pour des fautes de typo, pas grave j’ai pas test le code, et je vous emmerde tous :)

alexandre

Merci pour ces infos.

Je suis en train d’implémenter tout cela.

Je me demandais si tu avais eu une vrai réflexion pour memcached->pconnect au lieu de connect.
C’est réellement persistent ou bien c’est tout le long du script ?

Nico —

Merci pour ce partage, après la lecture je me suis empressé de tester mais il y a quelques points obscurs auxquels je ne trouve pas de réponse malgré quelques heures de recherche (3 jours en fait) :(

- On peut récupérer plusieurs items avec la méthode get() mais peut on envoyer plusieurs items d’un coup avec la méthode set() de memcache ?

- Quel est le poids maxi pour un item ?

- Quid de la sécu, n’importe qui peut écouter le port utilisé par memcached ? Comment protéger cela ?

- Faut-il préfixer les clés pour éviter un conflit entre 2 sites sur un même serveur qui utilisent Memcached ?

Cela fait pas mal de questions (désolé), autant de réponses intéressante.

alexandre

@nico : voici mes quelques réponses, que j’espère justes :
- set ne permet de stocker qu’un seul item à la fois
- le poids maxi d’un item doit être de la taille max de la mémoire allouée au serveur memcached (ce qui fait gros du coup). Je pense que le poids sera un élément bloquant ailleurs que dans memcached. Quelles sont tes contraintes de poids ?
- A priori, il n’y a pas de contrôle sur l’accès au serveur memcached. Il faut donc que la couche réseau sans occupe, avec un firewall donc. J’utilise iptables sous linux pour cela.
- J’avais pas pensé à préfixer les clefs, mais en effet, il faudrait. De plus, si plusieurs sites accèdent au memcached, il faut être sûr de leur confidentialité entre eux. Ce n’est pas un service à offrir sur un hébergement mutualisé.

flob9 —

Le maximum est de 1Mo par item, et oui c’est bien de prefixer les clefs quand il y a plusieurs applis.
Attention aussi à la taille des « slab », un memcached de 600Mo ne peut pas stocker 600 items de 1Mo, vu qu’il réserve des slabs de 512ko, 256ko, etc …

http://code.google.com/p/memcached/wiki/FAQ

Nico —

Un grand merci à vous 2 d’avoir pris la peine de me répondre !

@flob9 : 1mo + les slabs tu fais bien de le souligner !
Au passage je crois que c’est bytes pas ko.

@alexandre : « Quelles sont tes contraintes de poids ? »
Je n’ai pas spécialement de contrainte de poids, c’est surtout pour savoir si il est plus judicieux de stocker item par item ou un résultat entier (10 items).
1 Mo par item, ça va je suis largement en dessous (10ko par item environ) :)

Sans vouloir pousser, à quoi ressemble la commande Iptables qui permet d’autoriser l’écoute en local mais pas de l’extérieur ?

flob9 —

pour localhost pas besoin d’iptables; dans /etc/memcached/conf, tu as cette ligne à mettre (si elle n’y est pas déjà) :

-l 127.0.0.1

Nico —

Ok merci flob9 !

flob9 —

np
en fait c’est /etc/memcached.conf
pour vérifier que l’accès est uniquement en local :
#> cat /etc/memcached.conf | grep « \-l »
-l 127.0.0.1

Pour vérifier que c’est effectif :
#> netstat -lpn | grep memcache
tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN 2516/memcached

Là si tu as bien 127.0.0.1:11211 en 4eme colonne c’est ok, sinon c’est que t’as merdé, ou pas restart le demon memcached.

Après si tu as plusieurs serveurs, en effet il faut utiliser iptables, mais je pense que quand ce sera le cas tu ne posera plus tes questions sur ce blog ;)

Nico —

Nikel, encore merci pour ton aide ;)

Antoine —

Merci beaucoup pour cet article, c’est vraiment intéressant de comment est organiser l’infrastructure des gros sites internet.

By the way, quel est le logiciel que tu utilises pour faire tes schémas ? J’en recherche en vain depuis pas mal de temps.

Maxime

@Antoine : J’utilise LovelyCharts (http://lovelycharts.com/)

Antoine —

Merci ;)

D’autres articles sont prochainement prévus sur de l’admin sys ?

Maxime

@Antoine : Possible, dès que j’ai un peu de temps :)

Laisser un commentaire

Note : Pour qu'un commentaire soit affiché, votre e-mail doit être valide, et votre texte ne doit pas comporter d'insultes. Si vous ne respectez pas ça, n'essayez même pas de commenter.