L’infrastructure VDM : Memcache

Le 17 mars 2010 — par

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.

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é.

$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 :

/* 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 :

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.

S'abonner au flux RSS du blog
Recevoir les nouveaux articles par e-mail :