Le but de ce premier TP va être de se familliariser avec une partie de l'environement que l'on va utiliser au cours de ce cours.
Nous allons donc introduire ici deux concepts :
- Redis, un SGBD NoSQL très répendu et doté de fonctionnalités de programation répartie,
- Docker, un environement de virtualisation de conteneurs applicatifs.
Redis est un SGBD NoSQL Open Source orienté stockage clé-valeur. Il a trois particularités importantes :
- La base de données est entièrement gérée en mémoire, le disque n'est utilisé que pour la persistance,
- Il possède un jeu de types de données relativement riche comparé aux autres SGBD orientés stockage clé-valeur,
- Redis peut répliquer ses données sur de nombreux serveurs secondaires.
En plus de ces particularités, il possède quelques avantages :
- Il est très rapide avec 110000 insertions à la seconde et 81000 lectures à la seconde,
- Il supporte de types de données communs, comme des set, des hash, des list,
- Les opérations sont atomiques, en cas d'accès concurents, Redis conservera la valeur mise à jour,
- Il répond à d'autres besoins que du stockage clé-valeur, et peut être utilisé pour faire du message-queueing grâce à son support Pub/Sub natif, de la gestion de données temporaires ou à courte durée de vie comme des sessions utilisateur sur un site web, des opérations de comptage, etc.
Docker est un logiciel libre permettant d'automatiser le déploiement d'applications dans des conteneurs logiciels. Il nous permet de faire abstraction du système hôte pour l'éxécution d'un programme donné, d'isoler le programme du système hôte, de faire des applications réparties plus facilement scalable.
Dans le cadre de ce cours, Docker va nous permettre de contourner les restrictions des postes de l'IUT afin de pouvoir éxécuter n'importe quel SGBD NoSQL sans avoir à les installer ou configurer.
Notre projet nécéssite le lancement de plusieurs conteneurs :
- Un conteneur redis en mode SGBD (redis dans le fichier de configuration)
- Un conteneur redis en mode cli (rcli dans le fichier de configuration)
- Un conteneur readis (PHP) pour monitorer notre serveur redis
- Un conteneur phpRedisAdmin (PHP) pour interagir avec redis
Docker nous permet de définir des dépendance entre nos conteneurs, ainsi, nos conteneur PHP et notre conteneur redis CLI dépendent tout deux du conteneur redis SGBD.
Afin de lancer notre environement de développement, nous devons éxécuter la commande suivante :
docker-compose up -d
Cette commande va monter notre environement en téléchargeant les conteneurs directement depuis les dépôts de Docker et en démarrant et configurant ceux-ci.
Nous allons maintenant pouvoir nous connecter à notre conteneur redis CLI pour éxécuter des commandes sur notre conteneur redis SGBD par le biais de la commande suivante :
docker-compose run rcli
Nous sommes ainsi connectés dans notre conteneur redis CLI directement dans l'invite de commande de redis. Nous aurons donc uniquement accès aux commandes mises à disposition par redis.
À la fin de la séance, pensez à éteindre vos conteneurs avec la commande suivante :
docker-compose down
Nous allons maintenant pouvoir nous connecter à notre conteneur redis CLI pour éxécuter des commandes sur notre conteneur redis SGBD par le biais de la commande suivante :
docker-compose run rcli
Nous sommes ainsi connectés dans notre conteneur redis CLI directement dans l'invite de commande de redis. Nous aurons donc uniquement accès aux commandes mises à disposition par redis.
Redis nous propose différents types de données que l'on peut stocker :
- Des chaînes de caractères (binary safe),
- Des listes,
- Des sets,
- Des sorted sets,
- Des hashs,
- Des tableaux de bits.
Nous nous intéresserons qu'aux chaînes, aux listes, aux hashs et aux sets.
Redis nous permet de stocker en premier lieu des châines de caractères qui sont binary safe, c'est à dire que leur taille n'est pas délimitée par un caractère particulier. Nos clés comme nos valeurs peuvent contenir des caractères spéciaux. Vous trouverez l'ensemble des commandes pour les chaînes de caractère dans la documentation de Redis.
Nous allons commencer par stocker une simple chaîne dans Redis.
SET clef valeur
ou
SET clef "valeur"
En cas de réussite, redis vous répondra la chaîne OK
.
La commande SET
nous propose des options sur le comportement de la clé et sur le comportemant de l'insertion :
- On peut définir une expiration en secondes avec
EX
ou en millisecondes avecPX
. Ex :SET clef valeur EX 5
. - On peut définir une condition d'insertion
NX
(définie la clé-valeur seulement si elle n'existe pas) ouXX
(définie la clé-valeur seulement si elle existe déjà).
redis:6379> SET clef valeur XX
(nil)
redis:6379> SET clef valeur NX
OK
redis:6379> SET clef valeur NX
(nil)
redis:6379> SET clef valeur2 XX
OK
Maintenant que nous savons écrire des chaînes, nous allons les récupérées. Pour celà, Redis nous met à disposition une commande GET
:
GET clef
Cette commande ne prend pas de paramètres, elle retourne la valeur en cas de réussite, et null
(nil
) en cas d'échec (la clé n'existe pas).
Afin d'effectuer des opérations SET
et GET
sur plusieurs clés simultanément, Redis nous offres les commandes MSET
et MGET
.
redis:6379> MSET clef1 valeur1 clef2 valeur2
OK
redis:6379> MGET clef1 clef2
1) "valeur1"
2) "valeur2"
En plus de nous permettre de créer des chaînes de caractères et de les récupérées, Redis nous offre des commandes afin de les manipulées directement dans le SGBD.
Les premières commandes auxquelles nous allons nous intéressé sont les commandes INCR
et DECR
, permettant respectivement d'incrémenter et décrémenter des valeurs. Bien que l'on parle de chaînes de caractères, si nos valeurs représentent des nombres (qu'il soient entiers ou décimaux), ces commandes vont nous permettre de les manipulées comme des nombre. En cas de réussite, Redis nous retourne la nouvelle valeur.
redis:6379> SET visites 10
OK
redis:6379> INCR visites
(integer) 11
redis:6379> DECR visites
(integer) 10
Les commandes INCRBY
et DECRBY
permettent d'avoir un comportement similaire, mais nous imposent de définir le pas.
redis:6379> INCRBY visites 10
(integer) 20
redis:6379> DECRBY visites 5
(integer) 15
Les commandes SETRANGE
et GETRANGE
permettent de manipuler des morceaux de valeurs, en définissant ou récupérant partiellement les valeurs.
redis:6379> SET hello "Hello World"
OK
redis:6379> SETRANGE hello 6 "Redis"
(integer) 11
redis:6379> GET hello
"Hello Redis"
redis:6379> GETRANGE hello 0 5
"Hello "
La commande STRLEN
retourne la longueur d'une valeur, ou 0 si la clé n'existe pas.
redis:6379> SET hello "Hello World"
OK
redis:6379> STRLEN hello
(integer) 11
La commande APPEND
permet d'ajouter une chaîne de caractères à la fin d'une valeur.
redis:6379> SET hello "Hello"
OK
redis:6379> APPEND hello " World !"
(integer) 13
redis:6379> GET hello
"Hello World !"
Contrairement à SET
, MSET
ne permet pas de définir des conditions d'expiration ou d'écriture. Toutefois, une commande MSETNX
est mise à disposition pour éviter d'écraser des clés existantes.
À vous de jouer !
En utilisant les commandes vues précédement, créez les clés suivantes :
- user:1 avec pour valeur "Antoine"
- user:1:city avec pour valeur "Paris"
- user:1:age avec pour valeur "19"
- user:1:activity avec pour valeur "Running" et une expiration dans 10 minutes
- user:1:hobby avec pour valeur "Course à pieds"
- user:1:weight avec pour valeur "74"
Récuperez en une fois les clés que vous venez de créer pour city, age et hobby.
Définissez maintenant la clé user:1 avec pour valeur "Thomas" à condition que cette clé n'éxiste pas, puis définissez la clé user:1:city à "Amiens" à condition que cette clé existe.
Notre user a pris un an, et à perdu trois kilos grâce à la course à pieds. À l'aide des commandes Redis adéquates, modifiez ces valeurs. De plus, il fait le trajet régulièrement entre Amiens et Paris. Mettez à jour la valeur de la clé city à "Amiens/Paris" sans l'écraser complètement.
Notre user s'est mis à la course hippique. Sans écraser toute la valeur de la clé hobby, mettez à jour ce dernier. Récupérez la longueur de la clé hobby.
Pour finir, récupérez juste le fragment de valeur "Amiens" de la clé city.
Notre façon de gérer les données de notre user à l'exercice de la partie précédente n'est pas des plus optimales... En effet, nous avons créer de nombreuses clés à la racine de notre base. Afin d'éviter celà, nous allons utiliser des hashs.
Les hashs permettent de structurer les données sous forme de dictionnaires : à une clé correspond une valeur. Ceci nous permet de définir des "sous-clés" dans nos clés afin de regrouper tout ce qui concerne un object particulier.
Comme pour les chaînes de caractères, la documentation détaille les commandes disponibles pour les hashs.
De la même façon que pour les châines, Redis propose des commandes pour écrire et récupérer des hashs. Nous allons pouvoir écrire nos hashs avec HSET
et les lire avec HGET
.
redis:6379> HSET dictionnaire champ valeur
(integer) 1
redis:6379> HGET dictionnaire champ
"valeur"
Nous pouvons également définir plusieurs champs du hash grâce à la commande HMSET
et en récupérer plusieurs avec HMGET
. Un commande HSETNX
permet de faire un HMSET
si le champ n'existe pas.
redis:6379> HMSET bestiaire chat "Être perfide" chien "Meilleur ami de l'Homme"
OK
redis:6379> HMGET bestiaire chat chien
1) "\xc3\x8atre perfide"
2) "Meilleur ami de l'Homme"
Nous allons pouvoir tester l'existance d'un champ dans un hash avec la commande HEXISTS
, et supprimer des champs d'un hash avec la commande HDEL
. HEXISTS
retourne 1
si le champ existe, 0
le cas échéant, et HDEL
retourne le nombre de champs supprimés.
redis:6379> HMSET bestiaire chat "Être perfide" chien "Meilleur ami de l'Homme"
OK
edis:6379> HEXISTS bestiaire poisson
(integer) 0
redis:6379> HEXISTS bestiaire chat
(integer) 1
redis:6379> HDEL bestiaire chat chien cheval
(integer) 2
Nous avons également à disposition différentes commandes pour récupérer des inforamtions sur nos hashs. La commande HLEN
retourne le nombre de champs d'un hash, HKEYS
retourne les noms de champs d'un hash, HVALS
retourne les valeurs des champs d'un hash, HGETALL
retourne les champs et valeurs d'un hash.
redis:6379> HMSET bestiaire chat "Être perfide" chien "Meilleur ami de l'Homme"
OK
redis:6379> HLEN bestiaire
(integer) 2
redis:6379> HKEYS bestiaire
1) "chat"
2) "chien"
redis:6379> HVALS bestiaire
1) "\xc3\x8atre perfide"
2) "Meilleur ami de l'Homme"
redis:6379> HGETALL bestiaire
1) "chat"
2) "\xc3\x8atre perfide"
3) "chien"
4) "Meilleur ami de l'Homme"
À vous de jouer !
En utilisant les commandes relatives aux hashs, créez les dictionnaires suivants :
- Un dictionnaire user:2 contenant le nom "Dupont", le prénom "Etienne", un âge à 23
- Un dictionnaire user:3 contenant le nom "Dupond", le prénom "Charles", un âge à 21
HMSET ordis hp:pavillon "HP Pavillon" hp:stream "HP Stream" hp:envy "HP ENVY" asus:vivo "Vivobook" asus:chrome "Chromebook" asus:zen "Zenbook"
C'est l'anniversaire de notre user:2, à l'aide de la documentation, ajoutez lui un an.
Notre user:3 s'est trompé sur son âge, avec l'aide de la documentation, retirez-lui deux ans.
À l'aide de la documentation de la commande
HSCAN
, récupérez dans le dictionnaireordis
les ordinateurs dde marquehp
. Rappel : Par défault, nous travaillons dans la base (cursor)0
.Toujours à l'aide de
HSCAN
, récupérez les ordinateurs contenantvi
. Toujours à l'aide deHSCAN
, récupérez les ordinateurs finissants parbook
. Que remarquez-vous ?
Redis propose un ensemble de commandes pour manipuler des listes. Vous pouvez retrouver ces commandes dans la documentation.
Tout d'abord, nous pouvons ajouter des valeurs dans nos listes. Comme d'autres commandes pour les listes, il est possible de le faire pour le début de liste (L, comme left) ou pour la fin (R, comme right). Ainsi, nous disposons de deux commandes : LPUSH
et RPUSH
.
Pour récupérer des valeurs, nous avons sur le même principe les commandes LPOP
et RPOP
. Ces deux commandes enlèvent le dernier élément inséré au bout (gauche ou droit) de la liste.
redis:6379> LPUSH liste 1 2
(integer) 2
redis:6379> RPUSH liste 3 4
(integer) 4
redis:6379> LPOP liste
"2"
redis:6379> RPOP liste
"4"
On peut également insérer des éléments avec d'autres méthodes, et lire des éléments sans les supprimés de la liste. Nous pouvons parvenir à celà grâce aux commandes LINSERT
, LSET
et LINDEX
.
LINSERT
nous permet de faire de l'insertion grâce à un pivot, Redis recherche la première occurence de la valeur servant de pivot, et ajoute notre élément avant ou après celui-ci selon les options spécifiées. Cette méthode peut être coûteuse si la valeur pivot est située en fin de liste.
LSET
nous permet d'insérer un élement à un index particulier de la lsite.
LINDEX
à l'inverse permet de lire une valeur à un index particulier de la liste.
redis:6379> LPUSH liste 1 2 3 5 6
(integer) 5
redis:6379> LINSERT liste AFTER 5 4
(integer) 6
redis:6379> LINDEX liste 1
"5"
redis:6379> LINDEX liste 2
"4"
équivalent avec RPUSH
redis:6379> RPUSH liste 1 2 3 5 6
(integer) 5
redis:6379> LINSERT liste BEFORE 5 4
(integer) 6
redis:6379> LINDEX liste 3
"4"
Redis nous permet de supprimer des éléments d'une liste avec la commande LREM
. Cette commande prend en premier paramètre la liste, en second le nombre x
d'éléments à supprimer (si x
> 0, on en supprime x
en partant du début, si x
< 0, on en supprime x
en partant de la fin, si x
= 0, on supprime tout les éléments correspondants), et en dernier paramètre, les valeurs à supprimer.
redis:6379> RPUSH liste 1 2 1 2 3 1 2 3 4
(integer) 9
redis:6379> LREM liste 2 1
(integer) 1
redis:6379> LRANGE liste 0 -1
1) "2"
2) "2"
3) "3"
4) "1"
5) "2"
6) "3"
7) "4"
À vous de jouer !
Sans regarder la documentation, à l'aide des explications précédentes, expliquer ce que fait la commande
RPOPLPUSH
, prenant en paramètres une liste source et une liste destination.En lançant à nouveau redis cli dans un nouveau terminal (
docker-compose run rcli
et à l'aide de la documentation), expliquez et expérimentez les commandesBLPOP
,BRPOP
etBRPOPLPUSH
. Selon vous, quel peut-être l'intérêt de telles commandes ?
Comme pour les listes, les sets permettent de stocker plusieurs valeurs. La différence entre les listes et les sets réside dans le fait que les sets répondent à la théorie des ensembles. Comme pour les types précédents, la documentation détaille les commandes disponibles.
Nous allons retrouver les classiques commandes d'ajout, suppression, consultation et comptage d'éléments. (Note : Les éléments de sets sont appelés "membres")
redis:6379> SADD nombrespremiers 2 3 5 7 11 13 17 19 23
(integer) 9
redis:6379> SREM nombrespremiers 23
(integer) 1
redis:6379> SMEMBERS nombrespremiers
1) "2"
2) "3"
3) "5"
4) "7"
5) "11"
6) "13"
7) "17"
8) "19"
redis:6379> SCARD nombrespremiers
(integer) 8
La commande SISMEMEBER
permet de déterminer si une valeur est inclue dans un set.
redis:6379> SADD nombrespremiers 2 3 5 7 11 13 17 19 23
(integer) 9
edis:6379> SISMEMBER nombrespremiers 3
(integer) 1
redis:6379> SISMEMBER nombrespremiers 12
(integer) 0
La commande SDIFF
permet de soustraire plusieurs sets.
redis:6379> SADD chiffres 1 2 3 4 5 6 7 8 9
(integer) 9
redis:6379> SADD chiffrespairs 2 4 6 8
(integer) 4
redis:6379> SDIFF chiffres chiffrespairs
1) "1"
2) "3"
3) "5"
4) "7"
5) "9"
La commande SINTER
permet de faire l'intersection de deux sets.
redis:6379> SADD chiffres 1 2 3 4 5 6 7 8 9
(integer) 9
redis:6379> SADD chiffrespairs 2 4 6 8
(integer) 4
redis:6379> SINTER chiffres chiffrespairs
1) "2"
2) "4"
3) "6"
4) "8"
La commande SUNION
permet d'additionner deux sets.
redis:6379> SADD chiffrespairs 2 4 6 8
(integer) 4
redis:6379> SADD premierschiffres 1 2 3 4 5
(integer) 5
redis:6379> SUNION chiffrespairs premierschiffres
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "8"
À vous de jouer !
Antoine et Thomas organisent une soirée.
Antoine veut inviter : Sophie, Etienne, Hélène, Paul, Charles, Ethan et Pauline
Thomas lui souhaite inviter : Etienne, Paul, Catherine, Ethan, Pauline, Sophia et Mickaël
Ayant un espace limités, ils souhaitenant inviter uniquement leurs amis communs. Qui sont-ils ?
La semaine suivante, ils souhaitent organiser une soirée avec les personnes qui n'ont pas été invité à la première. À l'aide de la documentation, établissez une liste des invités d'Antoine et une liste des invités de Thomas dans de nouveaux sets.
Quelle-est la liste finale des invités pour cette seconde soirée ? Une fois établie, exportez-là dans un nouveau set avec l'aide de la documentation.
Il existe plusieurs opérations de base que l'on peut éxécuter sur les différentes clés. Ces opérations sont détaillées dans la documentation.
À vous de jouer !
Afin de vous préparer au TP noté qui aura lieu après la moitié du module, voici un exercice avec des conditions qui y sont similaires.
Arrêtez votre infrastructure avec la commande
docker-compose down
et relancez la avecdocker-compose up -d
afin de repartir d'une base propre.En travaillant à 1, 2 ou 3, vous saisirez vos réponses dans un document texte, du format de votre choix (texte simple, markdown, word, open office, pdf, ...), comportant vos noms, et avant chaque réponse, une ligne faisant référence au numéro de la question à laquelle vous répondez avec la format suivant :
#1
pour la question 1 par exemple.Si la réponse nécéssite plusieurs commandes, séparez-les par un simple retour à la ligne.
Question 1 : Définissez une clé "visits:omePge" avec une valeur à 10. Renomez ensuite cette clé à "visits:homePage".
Question 2 : Créez une liste "nombres" contenant les valeurs suivantes : 3 47 28 19 64 29. Triez la liste par odre décroissant et stockez le résultat dans une nouvelle liste "inverse".
Question 3 : Déplacez la liste "nombres" sur la seconde base redis.
Question 4 : Restaurez la valeur suivante dans une clé "paroles" avec un time to live de 10 minutes :
"\x00@HArgent j't'aurai avec ta couleur bizarre Sans qu'j'ai \xc3\xa0 faire le canard\b\x00]^\xc2\x80\xabk\xf3i"
. Maintenant, persistez la clé.Question 5 : Restaurez la valeur suivante dans une clé "suite" sans time to live :
"\x0e\x01;;\x00\x00\x007\x00\x00\x00\x14\x00\x00\xf2\x02\xf3\x02\xf4\x02\xf5\x02\xf6\x02\xf7\x02\xf8\x02\xf9\x02\xfa\x02\xfb\x02\xfc\x02\xfd\x02\xfe\r\x03\xfe\x0e\x03\xfe\x0f\x03\xfe\x10\x03\xfe\x11\x03\xfe\x12\x03\xfe\x13\x03\xfe\x14\xff\b\x00\xab\xf1\xaal\x90\\|\xd6"
. Déterminez son type.Question 6 : Récupérez les clés contenant la lettre
a
.Question 7 : Récupérez le temps de dernier accès à la clé "nombres". Réinitialisez ce temps sans lire ou écrire dans la clé.
Nous avons étudié les bases de Redis au cours de ce TP. Ceci nous a permis d'apprendre à utiliser un SGBD NoSQL orienté clé-valeur. Il existe d'autres SGBD NoSQL avec une orientation similaire, les plus connus sont Riak et Dynamo (disponible en tant que service cloud Amazon).
Pour aller plus loin sur Redis, la page documentation contient de nombreux liens vers des sujets divers, comme le pub/sub, le scripting en Lua, l'installation de modules complémentaires, la sécurisation de votre redis, la mise en place de cluster, etc.