POC: Design website accéléré par TokyoCabinet (part 1)

Tagged:

Je m'amuse, un Proof-Of-Concept avec PHP et tokyocabinet.

Ca fait un moment que j'entends parler de tokyocabinet, et j'ai eu 2/3 discussions avec des gens de différents avis à ce sujet. Je crois que je suis un peu rétrograde mais j'arrive pas a penser base de données sans penser modèle relationnel. Je persiste à croire que le SQL a de gros avantages et que le modèle key-value-store est génial dans une utilisation précise.

Et donc, j'ai imaginé comment j'intègrerai ça dans une application WEB pour profiter du randement énorme dont dispose un tel SGBD. L'avantage de ma solution c'est qu'elle peut être greffée à posteriori sur un site classique php/mysql ...

Alors attention: Usine à gaz comming soon ;) Je vais présenter d'abord l'idée, puis pas à pas sa réalisation.

1) Le principe :

Voila ;) Donc dans le principe, l'application WEB consulte toutes ses données à partir du key-value-store. Elle construit un hash à partir de l'url et 2/3 autres options, et elle récupère les données toutes construites. L'origine des données étant encore mysql et son SGBD relationnel de base.

Des taches que j'ai appelé ici "Admin" pompeusement, qui modifient les données modifient en fait mysql et insèrent une tache beanstalkd (un gestionnaire de tache à la volée) qui lui va construire les données nécéssaire aux pages à partir des données mysql.

Tokyocabinet devient une sorte de datamart , une vue sur la base de données, dans ce cas: orientée consultative et hyper rapide.

La ou réside un problème c'est lors de la création de nouvelles resources (l'affichage d'une page qui n'a jamais eu de données générée). Il faut que le site d'une manière ou d'une autre soit capable de réagire à une clé manquante dans le key-value-store, avec un message a l'utilisateur et un ajax call qui pourrait même montrer une barre de progression ou quelque chose comme ça ... A voir !

Il y a sans doute des api PHP pour lire directement les fichiers tokyocabinet, mais c'est très peu documenté, j'ai trouvé un truc là mais dans tous les cas je préfère utiliser tokyotyrant en frontend ça nous permettra d'utiliser tokyocabinet comme d'un MemCache, et d'installer le serveur en distant sur une autre machine.

2) Mise en oeuvre:

Je suis sous OSX avec macports depuis déja bien longtemps, beaucoup de choses installées donc s'il y a des trucs qui marchent pas chez vous ... faut chercher ;)

2.1) Tokyocabinet et leurs amis !

2.1.1) Installation

Je suis allé sur leur site chez sourceforce : j'ai pris dans packages : tokyocabinet, tokyotyrant, tokyodystopia pour chacun et dans l'ordre :

* ./configure
* make
* sudo make install

J'ai rencontré aucun soucis c'est déconcertant !

2.1.2) Premiers tests

En fait c'est pas très évident la façon dont tout ça fonctionne, donc pour un test je dirai :

Création de la DB:

* tchmgr create db.tch

Démarrer un serveur tyrant qui utilise cette DB:

* ttserver -dmn -host 127.0.0.1 -port 80808 db.tch

et voila ... de plus en plus déconcertant ce truc ;)

2.2) PHP

Donc comme chacun le sait il n'y a pas de PHP sans ZendFramework ... quoi, chacun le sait pas ?

Il faut juste installer memcache d'abord:

* sudo pecl install memcache

Puis on ajoute extension=memcache.so au php.ini puis reboot du serveur apache ! Vous pouvez vérifier avec un phpinfo() voir si on a bien l'extension de loadée.

Après avoir joué un peu, j'ai remarqué que le backend classique Memcache de Zend est soit buggé soit pas adapté pour tokyocabinet... Bref j'ai créé un TokyoCabinet.php dans un dossier Zend/Cache/Backend et voici le contenu :

<?php
 
class Zend_Cache_Backend_TokyoCabinet extends Zend_Cache_Backend_Memcached implements Zend_Cache_Backend_ExtendedInterface {
 
    public function load($id, $doNotTestCacheValidity = false) {
        $tmp = $this->_memcache->get($id);
        if (!empty($tmp)) {
            $tmp = unserialize($tmp);
        }
        if (is_array($tmp)) {
            return $tmp[0];
        }
        return false;
    }
 
    public function test($id) {
        $tmp = $this->_memcache->get($id);
        if (!empty($tmp)) {
            $tmp = unserialize($tmp);
        }
        if (is_array($tmp)) {
            return $tmp[1];
        }
        return false;
    }
 
}
 

J'ai juste rajouté la partie du unserialize qui manquait dans le Backend d'origine ... J'ai pas envie de tester si c'est normal, une autre fois peut être ;)

Du coup notre fichier d'exemple devient le suivant :

<?php
 
set_include_path('/home/workspaces/zend/framework/1.8.0/library' . PATH_SEPARATOR . get_include_path());
 
ini_set('display_errors', true);
ini_set('error_reporting', E_ALL);
 
require_once('Zend/Loader/AutoLoader.php');
Zend_Loader_AutoLoader::getInstance();
 
$cache_log =  new Zend_Log();
$cache_log->addWriter( new Zend_Log_Writer_Stream( 'file:///tmp/zf-memcache.log' ) );
 
# notre backend qui va pointer sur le serveur qu'on vient de créer
$cache_backend = new Zend_Cache_Backend_TokyoCabinet(array(
    "servers" => array(
        array("host" => "localhost", "port" => 80808)
    )
));
 
# le frontend de gestion logique
$cache_frontend = new Zend_Cache_Core(
    array(
    	'caching' => true,
    	'cache_id_prefix' => 'tokyo_test_',
    	'logging' => true,
    	'logger'  => $cache_log,
    	'write_control' => true,
    	'automatic_serialization' => true,
    	'ignore_user_abort' => true
    ) 
);
 
# le cache puis le test :
$cache = Zend_Cache::factory( $cache_frontend, $cache_backend );
var_dump($cache->save('Ici les data', 'monhash'));
var_dump($cache->test('monhash'));
var_dump($cache->load('monhash'));
 
?>
 

A lancer en cli ou en cgi, et dans mon cas ça me sort :

* boolean true
* int 1242860379
* string 'Ici les data' (length=12)

Super ça marche ;) Et c'est super rapide ... encore heureux à ce niveau là !

Bon demain on crée une base mysql de base avec un jeu de données, puis on s'attaque à beanstalkd.