Lancement du projet FineDB

Je travaille depuis quelques semaines sur un projet de base de données noSQL, que j’ai nommé FineDB (après mon projet de système de fichiers redondé FineFS, je vous laisse trouver le dénominateur commun).

Plusieurs choses ont amené cette idée à germer dans mon esprit :

  • Comme vous le savez, j’aime le C. À force de ne faire quasiment que du PHP, ça me manquait de travailler sur un bon projet en C. Quelque chose d’assez pointu pour manipuler des concepts assez bas niveau (réseau, threads), et pour lequel les performances soient primordiales − pour justifier l’emploi du C.
  • Il existe plusieurs bibliothèques de fonction permettant de gérer des fichiers de données. La vénérable BerkeleyDB a trouvé des remplaçants de qualité avec LevelDB de Google et LightningDB du projet OpenLDAP.
  • Il existe quelques autres bibliothèques que j’avais envie d’utiliser, comme Snappy (compression ultra-rapide de Google), Nanomsg (communication réseau par le créateur de ZeroMQ), ou encore MessagePack (sérialisation binaire) et TinyCC (compilation à la volée).

À partir de là, les pièces du puzzle se sont assemblées rapidement.

FineDB, c’est quoi

FineDB est une base de données noSQL, utilisant des paires clé/valeur.

FineDB est codé en C et est multi-threads. Les threads communiquent entre eux grâce à Nanomsg. Le moteur de stockage utilise LightningDB. Les données sont compressées à la volée avec Snappy (elles peuvent l’être au niveau du client ou du serveur).

Pour le moment, les fonctionnalités sont très simples : PUT (ajouter ou mettre à jour une clé), GET (récupérer le contenu associé à une clé), DEL (effacer une clé ; en fait un cas particulier du PUT), LIST (lister les clés présentes dans la base).
Il est possible de ne pas spécifier de base, et les commandes concernent alors la base par défaut. Sinon, il est aussi possible de spécifier le nom de la base à laquelle la commande est associée.

La base est toujours dans un état cohérent. Grâce au moteur de stockage utilisé, il est impossible de récupérer des données « en cours d’écriture ».

Le protocole de communication client-serveur se veut le plus efficace possible. C’est un protocole binaire (à la différence des protocoles textuels comme le HTTP), très compact.

FineDB, ça sert à quoi

À la base, FineDB vise la même utilité que Redis, Cassandra, Dynamo, Riak, CouchDB, Couchbase, Project Voldemort, MongoDB et tant d’autres. C’est-à-dire d’offrir un moyen de stocker des données référencées à partir d’un identifiant unique, en étant le plus performant possible.
(oui, je sais que certaines bases que j’ai citées sont orientées document et pas seulement clé/valeur, mais le principe reste valable dans sa globalité)

J’ai fait quelques petits benchmarks, avec des cas d’utilisation réelles (j’ai repris des données que je stocke en production dans un serveur Redis). Comparé à Redis et Couchbase, FineDB est globalement 2 fois plus lent en écriture et 2 fois plus rapide en lecture.
Ces benchmarks m’ont donné envie d’aller plus loin. Être plus lent en écriture s’explique par une meilleure persistance des données, qui sont stockées sur disque et non pas en RAM comme le font les autres (même s’ils ont des stratégies configurables pour stocker les données sur disque au final). Par contre, le fait d’être deux fois plus rapide que Redis en lecture est en soi un exploit intéressant qui peut suffire à légitimer l’existence de FineDB.

Le projet n’en est encore qu’à ses balbutiements. Pour le moment, je me suis attaché à prouver son potentiel. Si mes tests avaient montré des performances désastreuses par rapport aux systèmes déjà existants sur le marché, je ne serais pas allé plus loin.
Maintenant que je sais qu’il y a un intérêt à pousser les choses, j’ai pas mal d’idées à mettre en œuvre, notamment en ce qui concerne les questions de réplication, de redondance et de répartition. L’idée serait d’avoir un système de base de données noSQL qui puisse servir aussi bien sur un petit serveur isolé que pour mettre en place un cluster avec un grand nombre de machines.

Si je schématise, on utilise Redis sur un seul serveur, qu’on va parfois répliquer (en maître-esclave). Par contre, les clusters Redis sont encore instables et fonctionnellement dégradés. À côté de ça, on ne met en place du Hadoop que sur des infrastructures imposantes ; personne n’imagine installer un serveur Hadoop autonome, en dehors d’un cluster servant à du big data.
J’avoue m’intéresser de près à Couchbase, qui fait beaucoup d’efforts pour réunir le meilleur des deux mondes ; il est installable sur un serveur seul, mais il permet aussi de constituer des clusters facilement (avec une interface web absolument bluffante). Mais certains choix de design me feraient réfléchir par deux fois avant de l’utiliser sur mes applications professionnelles, j’imagine ne pas être le seul dans ce cas. Sans oublier que Couchbase n’est pas sous licence libre (même leur « Community Edition »), ce qui me gêne quand même un peu.

Les contraintes

Certaines contraintes de fonctionnement sont imposées par mes choix de design et par ceux des bibliothèques que j’utilise.

Les clés peuvent être longues de 64 KO au maximum.
Les données peuvent faire 4 GO au maximum.
(par comparaison, FoundationDB limite les clés à 10 KO et les données à 100 KO ; sur Amazon DynamoDB, clés et données sont limitées à 64 KO ; dans Couchbase, les clés sont limitées à 250 octets et les données à 20 MO)

Le nom des bases de données est limité à 255 caractères.

La taille des bases de données n’est limitée que par l’espace d’adressage virtuel. Concrètement, ça veut dire que c’est l’espace disque qui détermine la limite, et non pas la RAM disponible. LMDB se débrouille pour mapper les données en RAM pour accélérer leur accès (merci mmap). Par contre, il faut déclarer la taille maximal autorisée ; elle est de 10 MO par défaut (ce qui ne veut pas dire pour autant qu’un fichier de 10 MO est créé dès le départ).

Je ne pense pas que FineDB puisse être porté sous Windows ; trop d’appels POSIX sont employés (peut-être que ça pourrait marcher avec Cygwin mais j’en doute). Pour Mac OS X, ça devrait être possible, mais personnellement je n’ai que du Linux…

Le futur

FineDB évolue très vite en ce moment. J’ai revu certains aspects plusieurs fois, et cela va continuer un bon moment avant de se stabiliser. Je pense que le protocole va encore être modifié en profondeur une ou deux fois avant de prendre sa forme définitive.

Quand l’aspect mono-serveur sera pleinement opérationnel, je vais m’attaquer à la réplication maître-esclave. Une fois qu’elle sera en place, je passerai à la réplication maître-maître.
Si j’arrive à concrétiser les idées que j’ai en tête, je devrais pouvoir proposer quelque chose qui soit relativement simple à mettre en place et à administrer, mais aussi à coder.
Cela servira ensuite de support à un système de cluster, mais on verra ça en temps et heure.

Je réfléchis encore à la possibilité de faire évoluer FineDB vers un système orienté documents. Je me tâte encore beaucoup sur cette question, car cela pourrait faire chuter les performances. D’un autre côté, cet aspect pourrait être optionnel.

Je réfléchis aussi à un moyen d’ajouter des fonctionnalités au cœur du serveur. C’est quelque chose de complexe, mais TinyCC est tellement sexy (j’en ai déjà parlé l’an dernier) que je pourrais l’utiliser pour faire un système de plugins.

Où ça se passe ?

Comme pour mes autres projet, vous pouvez trouver les sources de FineDB sur GitHub : http://github.com/Amaury/FineDB

Comme je l’ai dit plus haut, le projet est encore en phase expérimentale. Je ne cherche pas spécialement de contributeurs, mais n’hésitez pas à me faire part de vos idées.

14 commentaires pour “Lancement du projet FineDB

  1. Salut,

    – Pourquoi avoir utilisé LightningDB plutôt que LevelDB ? c’est quoi d’ailleurs les différences majeurs entre les 2 ?

    – Pourquoi faire un système multi-thread alors que Redis est mono-thread par exemple ? est-ce que les opérations sont atomiques ?

    – Est-ce que tu vas rajouter d’autres commandes autre que les classiques GET/PUT/DEL/LIST, Redis a des structures de données intéressantes comme les ensembles, dictionnaires etc… ?

    – Est-ce que tu vas faire un binding pour PHP ou alors c’est inutile car on peut utiliser nanomsg pour communiquer avec le serveur ?

    Sinon c’est cool comme projet 🙂

  2. Super post, je vais me jeter sur les sources !

    Snappy a l’air super… même s’il est écrit en C++ !!! arg le sale traitre !!
    Pure C powaaaaaaaaaaaaa

    🙂

  3. Bonjour. un système de type Cluster est une très bonne idée. En revanche je pense qu’un mécanisme de réplication n’est pas la bonne approche pour atteindre un tel objectif. Cassandra est un bon exemple je crois dans ce domaine a contrario d’une approche a la MongoDB.

  4. @Renaud : Je n’en doute pas, tu es un vrai malade ! 🙂

    @stef : Il y a une implémentation de Snappy en pur C. C’est ce que j’utilise. Le seul problème, c’est qu’elle ne peut pas compresser au fur et à mesure, mais uniquement sur les données complètes ; ça impose des grosses recopies en mémoire, c’est pas forcément ce qu’il y a de plus optimisé.

    @fred : En résumé, LightningDB est en pur C, alors que LevelDB est en C++ (mais il existe un wrapper C). Et d’après un benchmark − que je n’arrive évidemment plus à retrouver − LightningDB est un poil plus rapide que LevelDB.

    Tu peux faire du mono-thread tant que tu n’as aucun opération bloquante. Il est possible de gérer la communication réseau en asychrone (avec libevent ou libev par exemple) pour qu’elle ne soit pas bloquante, mais les appels à Snappy et LMDB sont relativement gourmands. Il est plus efficace de les faire traiter par des threads séparés, pour que cela n’ait pas d’impact sur les autres requêtes en cours de traitement.

    Je m’en tiendrai aux paires clé/valeur, je n’ajouterai pas de fonctionnalités de listes et autres comme Redis. Cela pour 2 raisons : La première, c’est que LightningDB ne gère que des paires clé/valeur. La seconde, c’est que je ne suis pas convaincu de leur utilité ; je trouve que ça complexifie la compréhension des développements ; je préfère de loin mixer SQL et noSQL.
    Comme je l’ai écrit dans l’article, je réfléchis plutôt à la possibilité de stocker des documents en base, avec tout ce qu’on peut imaginer à partir de là (faire du map/reduce, notamment).

    La communication avec le serveur se fait avec des sockets classique (nanomsg n’est pas encore supporté par beaucoup de langages). L’idéal serait évidemment de faire des clients de connexion natifs pour chaque langage ; mais en attendant, il est très simple d’écrire une bibliothèque cliente qui ouvre une socket pour communiquer avec le serveur.

  5. @stéphane bunel : Je pense qu’il s’agit plutôt d’approches différentes, qui répondent à des besoins différents.

    On fait de la réplication quand on veut redonder les données. Toutes les données peuvent tenir sur un seul serveur, mais on souhaite :
    – soit accélérer les lectures en les répartissant sur plusieurs machines ;
    – soit améliorer la sécurité des données, par exemple en mettant en place un esclave qui prendra la place du maître si celui-ci tombe en panne.

    On met en place des clusters quand on veut répartir les données. Habituellement parce qu’on a tellement de données qu’elles ne peuvent pas tenir sur un seul serveur ; mais ça peut aussi être fait pour améliorer les performances, en répartissant les débits réseaux et les accès disques sur plusieurs machines. Enfin, les clusters peuvent servir aussi à répartir les calculs (map/reduce).

    Mon idée est de proposer une brique qui puisse être utilisée seule (serveur standalone). On peut placer plusieurs briques les unes à côté des autres (réplication maître-esclave). On peut joindre plusieurs briques avec du mortier (réplication maître-maître, avec du logiciel supplémentaire pour gérer la communication entre les serveurs). Ou on peut carrément monter des murs (clusters dans lequel les données sont réparties sur certains serveurs, alors que les méta-données sont redondées sur d’autres, avec du logiciel supplémentaire pour gérer tout ça).

  6. @Amaury, je vais prendre ça comme un compliment 🙂

    Cela dit, quand tu auras une doc du protocole, je me sens bien de faire la classe cliente 🙂

  7. @Renaud : Bien sûr que c’est un compliment ! 🙂

    Ah, cool pour la lib cliente. Bon, je t’avoue que j’aurais déjà un peu de code PHP fonctionnel sur lequel tu pourras te baser. Pour me simplifier les choses, je fais mes benchmarks en PHP ; c’est le moyen le plus simple − pour moi − pour attaquer à la fois du FineDB, du Memcache, du Redis, du Couchbase, …

  8. J’ai retrouvé le benchmark qui comparait LightningDB et LevelDB (ainsi que BerkeleyDB, SQLite et Kyoto TreeDB) : http://symas.com/mdb/microbench/

    LevelDB est un peu plus performant en écriture, mais LightningDB est très largement devant en lecture. Et comme j’ai la vision qu’une donnée écrite est lue au moins une fois, et souvent un très grand nombre de fois, il me semble logique de privilégier la lecture. Sachant qu’en plus LightningDB ne se fait battre par LevelDB que dans certaines situations, et qu’il est devant les autres moteurs de stockage dans tous les cas.

    Ce benchmark est fait par les créateurs de LightningDB, mais il semble sérieux.

  9. @Frank : En lisant les papiers de recherche de Google, qui décrit leur infrastructure, on peut voir qu’ils parlent de « Zippy » tout le temps. Pendant longtemps, Zippy n’était pas disponible, jusqu’à ce qu’il soit ouvert son le nom de Snappy.
    J’avoue ne pas avoir cherché plus loin. Ce qui est bon pour Google devrait me convenir.

    Mais tu as éveillé ma curiosité. Je vais regarder LZ4 sans tarder ! 🙂

  10. Salut, quelle est la différence avec MemcacheDB (LMDB) en dehors de l’interface de connexion ?
    https://github.com/LMDB/memcachedb

    D’ailleurs en parlant de l’interface de FineDB j’ai vu que GET ne peut récupérer qu’une seule valeur à la fois alors que le GET de Memcache peut prendre un tableau (donc moins d’overhead ?)

  11. @Vince : Je n’avais pas vu ce projet. Utiliser le protocole de Memcache est une très bonne idée. Cela permet d’être nativement compatible avec tous les clients existants. Mais ce projet n’a pas évolué depuis longtemps ; soit il fait ce qu’il a à faire (et dans ce cas c’est dommage qu’il n’ait pas été plus mis en avant), soit il a des lacunes…

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Notifiez-moi des commentaires à venir via email. Vous pouvez aussi vous abonner sans commenter.