Redis et la séparation des données entre les projets

Première publication : 2012-04-25
Tags : redisnosql

Le 24 avril, Geoffrey Grosenbach demandait si on utilise des bases Redis (internes à une instance du serveur) différentes pour chaque projet, ou bien une seule, en espérant qu’il n’y ait pas de collision de clés. Cet article présente la manière de faire que j’ai adopté.

Rappel

Redis est une base de données “clés/valeurs”. C’est une manière de stocker et accéder aux données très différente des système relationnels tels que MySQL, Oracle…

Pour comprendre le fonctionnement de Redis, je conseille la lecture du livre de Karl Seguin : The Little Redis Book.

Le serveur Redis (redis-server) est une application autonome, qui fonctionne avec un seul thread, accessible via un port TCP ou bien un socket système.

Il dispose de plusieurs bases internes, dont la seule distinction est un numéro d’ordre. Il y en a 16 par défaut (c’est configurable) et si le client ne spécifie pas de base particulière, il est connecté à la première (numérotée 0).

Au sein d’une base, Redis stocke des objets typés (les valeurs), accessibles par un index unique (les clés). Une clé est une simple suite de caractère, par exemple metrics:users:count. Le choix du : comme séparateur “sémantique” est totalement arbitraire et laissé au choix du développeur et permet de facilement reconstituer mentalement une arborescence de clés. Aux yeux de Redis, l’exemple précédent est strictement identique à metrics/users/count, MetricsUsersCount ou même hello.

Séparer ses données

Lorsqu’on manipule des données dans des contextes différents le risque est de contaminer les données d’un contexte depuis un autre contexte. Il convient alors d’utiliser un système qui permet de ne pas mélanger les données selon le contexte. Pour un projet qui peut fonctionner dans des environnements de test, développement et de production, les données doivent être partitionnées.
Si on a plusieurs projets en simultané, il faut également séparer leurs données.

La première approche est d’utiliser un espace de nommage. Encore une fois, pour Redis ça n’est pas une fonction particulière, mais juste une convention de nommage des clés. On peut alors préfixer nos clés par le nom du projet et son environnement : projet1:dev:metrics:users:count sera alors bien séparé de projet2:prod:metrics:users:count.

Le problème avec cette approche est que pour Redis, tout est dans le même panier. Il devient impossible de supprimer toutes les clés du “projet 1” uniquement. De même parcourir le contenu de la base à la recherche d’une clé est moins facile.

On peut alors utiliser une base interne différente pour chaque projet. Il conviendra alors au client de se connecter à la bonne base, mais ensuite tout est bien séparé.

Le problème est que Redis ne permet pas de nommer les bases internes, elles sont simplement numérotées. Il n’y a pas non plus de configuration particulière pour les bases (persistance, sécurité…). Rien n’empêche un client de se connecter à la mauvaise base d’y mettre la pagaille.

De plus, le support des bases internes multiples va être déprécié ne sera pas supporté dans Redis Cluster, il est donc prudent d’étudier une autre alternative.

Il reste une troisième solution ; 1 serveur Redis par projet.

Configurer et utiliser plusieurs instances

Le serveur Redis est un simple binaire qui n’a aucun mal a être lancé plusieurs fois en parallèle. Par défaut il va chercher sa configuration à un emplacement prédéfini, mais rien n’empêche de le lancer avec une configuration spécifique à chaque fois.

Les variations minimales à faire entre les configurations sont au moins le moyen d’accéder à l’instance (port TCP ou socket système) et l’emplacement des données.

Il suffit de créer un fichier de configuration et un script d’initialisation pour chaque instance et le tour est joué.

Le choix d’en faire une pour chaque environnement au sein d’un même projet n’est pas si compliqué :

  • sur un serveur il n’y a le plus souvent que l’instance de “production” ;
  • sur le poste d’un développeur, il peut y avoir une instance de “développement” (permanente ou lancée au besoin) ;
  • pour un environnement de “test”, on peut avoir une instance démarrée à la volée, sans persistance sur le disque. Elle est donc re-initialisée à chaque fois, ce qui convient assez bien à ce type d’usage ;

Avantages des instances multiples

Il existe plusieurs grands avantages à utiliser Redis de cette manière

Une séparation stricte des données ; une fois connecté à un serveur, seules les données qu’il gère sont accessibles, sans risque de pollution. La sauvegarde/copie/déplacement des fichiers de persistance devient triviale, le vidage éventuel d’une base devient sans risque pour les autres données.

Une configuration adaptée ; il est possible de gérer la persistance des données de manière différente pour chaque instance, mais aussi d’utiliser un socket système pour certaines et un port TCP pour d’autre, des protections par authentification (ou pas), ou tout autre paramètre de configuration.

Une utilisation à la demande ; il est possible de ne lancer telle ou telle instance du serveur que lorsque c’est nécessaire. Sur un serveur en production, elles seront probablement toutes lancées en même temps, mais en développement ou sur un serveur d’intégration continue ça peut être utile (avec Foreman par exemple).

Une supervision spécifique ; on peut mettre en place des outils de supervision adaptés à chaque instance en fonction de son niveau de criticité. Une instance critique pourra être suivie de très près (y compris avec des tests sur la présence de clés/valeurs spécifiques), avec des graphiques exhaustifs sur les ressources… Dans le même temps, une autre instance pourra être simplement testée sur le fait que son processus est bien présent et rien d’autre.

Il est important de noter que chaque instance du serveur Redis n’occupe qu’environ 1 Mo de ram (hors données stockées). le surcoût est donc minime, voire négligeable.

Conclusion

À partir du moment où plus d’un projet doit accéder à une base de données Redis, je ne vois que des avantages à disposer d’une instance de redis-server pour chaque projet.