Docu­ment store à recom­man­der


J’ai un modèle rela­tio­nel très complexe avec des règles métier des plus biscor­nues quand on souhaite relire quelque chose. Par exemple, pour récu­pé­rer le libellé d’un item il faut que je conca­tène plusieurs champs et que je fasse une ou deux condi­tions pour gérer des cas spéci­fiques.

J’ai peur que ça devienne diffi­cile à gérer et que ça faci­lite énor­mé­ment les erreurs de trai­te­ment à l’ave­nir.

J’ai envi­sagé les trois solu­tions clas­siques :

  • dénor­ma­li­ser le modèle en stockant à plat certaines données préca­lu­lées dans le SGBDR, mais il y a pas mal de choses où c’est vrai­ment déli­cat, par exemple quand un item contient une collec­tion de données
  • coder des vues complexes et des procé­dures stockées pour auto­ma­ti­ser certaines actions, mais j’ai l’im­pres­sion de dépor­ter mon métier là où ça sera le plus diffi­cile à main­te­nir et à déve­lop­per
  • ou utili­ser un bête stockage orienté docu­ment et lais­ser tomber le rela­tion­nel, qui de toutes façons me sert assez peu sur ces données

À priori je suis plutôt parti sur la troi­sième solu­tion et j’ai besoin de vos lumières pour choi­sir le datas­tore le plus adapté.

Voici mes contraintes :

  • Perfor­mant (c’est pour utili­ser en perma­nence au cœur de l’in­fra)
  • Acces­sible faci­le­ment en PHP
  • Stocke des données struc­tu­rées (type json) avec de la hiérar­chie (un docu­ment peut conte­nir une collec­tion par exemple)
  • Le modèle de chaque docu­ment doit être libre ou en tout cas très souple
  • Sait mani­pu­ler une collec­tion de plusieurs millions de docu­ments (d’où la néces­sité des index au point précé­dent)
  • Sur ces millions de doc je peux faire des requêtes de type « par date de mise à jour inverse, unique­ment ceux qui ont un attri­but ‘toto’ à 145 et un attri­but ‘tata’ à 567 » sans avoir à faire un scan de tous les docu­ments à la requête (ce qui implique proba­ble­ment des index)
  • Sait gérer de la haute dispo­ni­bi­lité (par exemple deux serveurs synchro­ni­sés en master-master)
  • Simple à utili­ser et admi­nis­trer
  • Stockage disque (donnée pérenne en cas de plan­tage)
  • Accès réseau (la base et l’ap­pli­ca­tif sont sur des serveurs diffé­rents)

J’ai aussi des non contraintes :

  • Les écri­tures sont faites en batch, je n’ai pas besoin de tran­sac­tion ou de lock d’écri­ture
  • Je n’ai pas besoin de vali­da­tion, typage, ou contrainte d’in­té­grité
  • Je n’ai pas besoin de tran­sac­tions
  • En cas de plan­tage, j’ac­cepte de perdre quelques minutes de données non écrites (mais pas de plan­ter les anciennes données)
  • J’ac­cepte des latences jusqu’à quelques minutes entre les diffé­rents serveurs synchro­ni­sés
  • Je peux prévoir à l’avance les requêtes que je vais faire (et donc construire des index dédiés)

Les bonus :

  • Consom­ma­tion mémoire pas trop déli­rante
  • Outil pour faire des dump/restore

Cassan­dra, Volde­mort, MongoDB et autres joyeu­se­tés, je suis preneur de vos recom­man­da­tions avec expli­ca­tions, ou simple­ment des liens vers des billets qui peuvent m’éclai­rer.

Merci à vous cher public (j’ai toujours rêvé de dire ça ;)


9 réponses à “Docu­ment store à recom­man­der”

  1. C’est une réponse peut être hors sujet, mais si ton seul soucis est de chercher, tu peux garder ton système de stockage actuel et indexer tes données en temps réel avec ElasticSearch.
    Ça supporte pratiquement tous les points requis, même si pour des questions de performance il vaut mieux lui fournir un schéma le plus complet possible avant d’indexer (quitte à lui filer des données incomplètes). Tu peux aussi faire des queries très complexes en javascript, si les possibilités de recherche de base (assez étendues) ne te suffisent pas.

    • Au vu de tes contraintes, je seconde la recommandation de CouchDB.

      Si tu relâches la contrainte de réplication Master-Master, et que tu acceptes une réplication Master-Slave(s), avec élection d’un nouveau Master en cas de perte du Master, tu peux aussi aller vers MongoDB.

      Dans les deux cas, tu devras construire des index en fonction des requêtes que tu veux faire, mais ça se fera un peu différemment. Avec CouchDB, un index est une « vue » que tu exprimes généralement avec un petit bout de Javscript. C’est très flexible, mais un peu déroutant au début. Avec MongoDB, ça ressemble plus à ce que tu ferais avec du SQL, où tu te contentes d’ajouter un index sur une colonne.

  2. > Cassandra, Voldemort, MongoDB

    Attention c’est pas pareil :
    – Cassandra : orienté colonne
    – Voldemort : orienté clé/valeur
    – MongoDB : orienté document (document pouvant contenir des valeurs simples – string, int, etc – ou complexes, par exemple clé/valeur)

    Après, choisir n’est pas simple du tout. A priori une orienté document serait intéressante, mais même dans ce cas il y a plusieurs choix, entre autre MongoDB vs CouchDB

    La première chose est donc de voir précisément quel type de stockage est intéressant. Ensuite, faut choisir dans les possibilités, sachant que beaucoup proposent une interface REST avec du Json (donc c’est accessible par le réseau, entre serveurs ou depuis le client, etc) Bon parfois il y a aussi du BSON plutôt que JSON.

    Quelques liens :
    * Pour comparaison de différentes solutions (et explication) : http://www.smile.fr/Livres-blancs/Culture-du-web/NoSQL
    * Pour comparaison de cassandra, mongodb, couchdb, redis, riak, … http://kkovacs.eu/cassandra-vs-mongodb-vs-couchdb-vs-redis
    * Comparaison MongoDB – CouchDB (en prenant en compte que c’est sur le site de MongoDB) http://www.mongodb.org/display/DOCS/Comparing+Mongo+DB+and+Couch+DB

    Bon, évidemment c’est encore une réponse du type « faut voir » mais avec de quoi commencer. Dans tous les cas je dirais qu’il y a deux étapes principales : choix du type de stockage puis choix de la solution exacte.
    Le problème au final c’est que NoSQL regroupe pas mal de choses assez différentes.

    Et histoire de rajouter une solution beaucoup plus… heu… particulière : https://gist.github.com/2715918
    En gros, comment faire de l’orienté document avec stockage json dans un PostgreSQL. Je ne suis pas sur que ça puisse répondre mais c’est une solution qui peut parfois être envisageable s’il y a déjà du postgres dans l’infra par exemple.

  3. Comme déjà dit, ton besoin semble t’orienter naturellement vers de la base documentaire. Après, je dis « ton besoin », mais ce n’est pas réellement ton besoin que tu nous as présenté, mais plutôt tes pré-choix ;)

    La bonne manière pour choisir son moteur c’est plutôt de se demander de quelle façon on manipule les données. Là tu as effectivement parler de champs dont la valeur dépend d’autres champs, mais ça à la limite c’est hors-sujet: soit c’est du côté de l’application et on se fout du mode de stockage, soit c’est pré-calculé et ce n’est qu’un champ parmi d’autres et là encore on se fout du stockage. Ce n’est pas un cas qui permet de discriminer les solutions qui s’offrent à toi.

    Tu as énoncé des besoins techniques qui permettront sans doute d’éliminer certaines solutions.

    Après pour le choix final, à mon avis les bonnes questions sont plutôt:
    * Est-ce que j’ai besoin de sortir des statistiques à partir des documents (par exemple combien de fois tel livre a été lu, et par quel groupe) ? Comment souhaité-je remplir ces statistiques ? À quelle fréquence doivent-elles être à jour ?
    * Est-ce que j’ai besoin de résoudre certaines relations (par exemple les livres par le(s) même(s) auteur(s), les livres traitant du même sujet) ? Ça permet généralement de définir en plus comment on va modéliser les données.

    Bref, plutôt des questions sur la façon dont seront utilisées fonctionnellement les données, qui permettra de savoir sur quel cas se concentrer et permettra de définir le choix idéal comme étant le moteur de stockage gérant le mieux ces choix.

    Cela dit ton besoin de réplication et de disponibilité semble t’orienter vers du NoSQL. Tu n’auras pas forcément envie de te retourner complètement l’esprit donc on peut virer les key/value et les bases graphes, qui obligent à changer complètement notre mode de réflexion lors de la modélisation.
    Une base documentaire sera plus simple à utiliser et le modèle sera plus simple à concevoir.

    Du coup on revient aux classiques MongoDB ou CouchDB (je ne t’ai donc pas plus avancé que les commentaires précédents, mais tu sais déjà un peu mieux pourquoi on arrive à ce duo ;)).

    Pour résumer ce que je connais de leurs différences (les articles cités par CrEv complèteront):
    * CouchDB est à mon avis bien plus complexe d’utilisation, le mode de requêtage par vue est vraiment difficile à appréhender au début, la courbe d’apprentissage est plus raide que MongoDB.
    * CouchDB gère *réellement* les fichiers attachés. Ce sont des entités bien définies, et c’est plus simple à gérer que GridFS (je ne sais pas si tu as ce besoin).
    * CouchDB versionne nativement les documents. C’est cool :)

    Pour le reste je sais que MongoDB gère les index, qu’il a un systême de procédures stockées ultra simple (tu sauves une fonction JS dans ta base…) qui pourrait bien te servir pour tes calculs de champ composé. Je ne connais pas assez CouchDB pour te dire s’il bénéficie aussi de ces fonctionnalités ou pas.

  4. Pour la haute disponibilité, je ne sais pas si les Replica Set de MongoDB te conviennent…
    Pour la RAM, je ne sais plus comment fonctionne CouchDB mais Mongo stock le maximum dedans (filecache géré par l’OS en fait).
    Etant dénormalisée, chaque « nom de colonne » devient un nom de champ et est donc répliqué dans chaque document, d’ou une empreinte mémoire plus lourde.

    Regarde entre CouchDB et MongoDB ce qui te convient le mieux (feature / suivi de l’entreprise derriere).

    Le seul point noir de MongoDB est la lenteur pour avoir certaine feature : ex : https://jira.mongodb.org/browse/SERVER-831 (c’est dispo que sur un étage mais pas plus).
    Ceci dit à coté ils[10gen] bossent sur d’autres features: le framework d’aggrégation, hyper simple à maintenir / travailler en équipe / debugger, bien plus simple que du Map/Reduce, du search amélioré etc…

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.