Je vous propose de découvrir Redis. Base NoSQL en mémoire, c’est le système de stockages des données utilisé par ZapTravel, société pour laquelle je travaille depuis mai 2012. Nous avions le choix de prendre MongoDB ou autre, mais finalement la simplicité et la puissance de Redis sont bien adaptés. Je vous propose de vous faire découvrir Redis, de A à Z avec quelques exemples. Une partie de cet article est à créditer à Ross Tuck qui a présenté Redis à Confoo. Si vous avez l’occasion de voir cet excellent speaker, ne manquez pas cette opportunité. Peut-être à Devoxx Belgique 2013. A suivre.
Introduction
Redis est classé dans la catégorie des bases NoSQL. Mais finalement comme disait Ross Tuck à Confoo, Redis est plus une base No-NoSQL (not only noSQL). C’est une base clé-valeur en mémoire, qui peut éventuellement persister sur disque les données. Redis propose différentes structures de données. De la simple clé/valeur au SortedSet en passant par la liste à double entrées… nous allons voir cela dans quelques instants.
Redis est une solution open-source codée intégralement en C par Salvatore Sanfilippo (@antirez). A noter qu’il est sponsorisé par VMWare ce qui lui permet de travailler sur Redis, et ce qui assure aussi le support d’un éditeur pour son développement. Lors de sa présentation, Ross cite quelques sites Internet à fort traffic qui utilisent Redis comme par exemple le site pour adulte YouPorn (présentation ici et détails ici) qui, avec 200 millions de visiteurs par jour, tient bien la charge.
Redis est avant tout un serveur de données en mémoire. Il est vraiment rapide. Une machine classique comme un Mac i7 sort sans problèmes 120 000 opérations par seconde. Autant dire que si vous ne voulez pas de contention, c’est une solution à étudier de près. Mais vous allez le voir, en dehors des performances, c’est aussi la simplicité du modèle de programmation qui m’a séduit.
Redis est par définition multi-threadé mono-threadé (plus d’explications ici) et donc mono-coeurs. Son architecture est similaire à Node.JS ou PlayFramework. C’est une architecture événementielle non bloquante. Redis utilise cependant sa propre implémentation du gestionnaire d’événements. Globalement, Redis est donc dans la mouvance de ces nouvelles architectures non bloquantes et réactive, ce qui en fait, vous pouvez l’imaginer, un très bon compagnon de Play2+Scala.
Réplication
Y-a-t-il du sharding ? Non, pas de division physique des données. S’il y a un partage à effectuer, ce sera à vous, en tant que développeur, de faire ce choix. Sur Zaptravel nous avons 2 familles de serveur Redis. D’une part tout ce qui concerne les données statiques et d’autre part les données dynamiques. Par données statiques, j’entends tout ce qui est description des villes, des hôtels, des activités ou les noms des places à visiter. Ce type de donnée n’a pas besoin d’être mis à jour fréquemment. C’est aussi ici que nous stockons les adresses des images de Zaptravel. Quant aux images elles-mêmes, elles sont sur Amazon S3. Pour les données dynamiques, nous avons besoin de mises à jour plus fréquentes (toutes les 10 minutes). Il s’agit pour l’essentiel des prix et des disponibilités. Au lieu d’essayer de tout mettre dans une base, puis de la diviser sur plusieurs serveurs, nous utilisons simplement 2 gros serveurs (8Go et 16Go) pour stockers ces données. Et c’est suffisant pour nos besoins. En charge je pense que nous n’aurons pas besoin de plus de 25Go pour faire tourner un site avec 870 000 pages différentes. Je parle bien ici de données, pas de mémoire. Si vous voulez savoir avec quoi tourne www.zaptravel.com, et bien c’est simple : avec moins de 1Go de mémoire vive. Pas besoin de plus.
Sur Redis, il est possible de configurer des serveurs en maître-esclave. Vous pouvez avoir aussi une chaîne de serveur, ce qui est pratique. En tant que développeur, je configure mon MacBookPro comme étant un slave de ma machine de préprod, et j’ai ainsi en local tout ou partie de mes données. Imaginez que vous puissiez travailler avec une base MySQL/Oracle sur votre ordinateur, que celle-ci se mette à jour automatiquement à partir de vos machines de prod ou de préprod… C’est tellement simple qu’il est possible de passer des tests de non-régression sur des données copiées de la prod, et ainsi de tester différents scénarios de codes.
Sur Redis il est aussi possible de s’abonner afin d’être notifié lorsqu’un élément est ajouté sur une liste. Une sorte de MessagingQueue en quelques sortes. Vous pouvez aussi gérer des Transactions, mais sur ce point je vais détailler. Par défaut, le coeur de Redis qui effectue l’écriture en mémoire est mono-threadé. Comme à un instant T, une seule Thread est chargée d’écrire, alors il n’y a pas de problèmes d’isolation sur une clé donnée. Cependant il peut y avoir un problème de cohérence, lorsque vous écrivez sur plusieurs clés différentes. Pour éviter cela, il est possible et fortement recommandé d’utiliser les Transactions. En fait je vois plus cela comme la notion de « Batch ». Il s’agit d’envoyer en une seule opération tout un ensemble d’opérations d’écritures. C’est redoutable d’efficacité lorsque vous devez effectuer des traitements importants. Concernant le « temps » que cela prend, on est en dessous de 4 ou 5ms… Donc voyez plutôt la notion de Transaction comme un moyen d’éviter de coûteux aller-retours réseaux, pour envoyer en un seul batch, tout un ensemble de commandes.
Installer Redis
Redis s’installe sur Mac avec homebrew, et avec apt-get sur Linux. Le site https://try.redis.io/ vous permet de tester et d’apprendre en quelques minutes les commandes de Redis.
Redis-cli
Pour découvrir Redis, dans un autre terminal, lancez le client redis qui vous permet de vous connecter directement sur le serveur. Nous utiliserons redis-cli pour tester et interroger le serveur directement. Les clés et les valeurs sur Redis sont forcément des Strings.
Lancez la commande redis-cli. Une fois connecté, tapez « info » puis entrée afin de voir l’état du serveur.
nicolas@macbook :~/Dev/redis-2.6.12> redis-cli
redis 127.0.0.1:6379> info
# Server
redis_version:2.6.12
redis_git_sha1:00000000
redis_git_dirty:0
redis_mode:standalone
os:Darwin 11.4.2 x86_64
arch_bits:64
multiplexing_api:kqueue
gcc_version:4.2.1
process_id:7834
run_id:3a2cb23182420eaa35c6c82c06878e70d60beed6
tcp_port:6379
uptime_in_seconds:4
uptime_in_days:0
hz:10
lru_clock:184727
...
...
Bon, il est temps de commencer à découvrir les commandes Redis. Ce que nous allons voir vous servira directement lorsque vous coderez en Java, en Scala ou en PHP. Les drivers Redis reprennent la syntaxe de l’interpréteur. Si vous maîtrisez les commandes, vous êtes alors capable de programmer avec Redis. Nous sommes en pur client/serveur. D’ailleurs vous pouvez aussi faire un telnet 6379, vous verrez que Redis vous accueille comme un grand. Il n’y a donc pas de BSon ou de binaire entre le client et le serveur.
Vos premières clés/valeurs
Allons-y, nous allons créer des entités type clé-valeurs très simple. La syntaxe est SET <key> <value>
redis 127.0.0.1:6379> set Webuser:1 Nicolas
OK
redis 127.0.0.1:6379> set Webuser:2 Paul
OK
redis 127.0.0.1:6379> set Webuser:3 Pierre
OK
redis 127.0.0.1:6379> KEYS Web*
1) "Webuser:2"
2) "Webuser:3"
3) "Webuser:1"
redis 127.0.0.1:6379>
Plus intéressant, SETEX permet de stocker une clé temporaire qui expire au bout de 10mn dans cet exemple. La commande TTL vous donne le nombre de secondes avant que Redis n’efface cette clé. Je vous laisse envisager ce que cela vous permet de faire 🙂
redis 127.0.0.1:6379> setex Webuser:Tmp 600 TempVisitor
OK
redis 127.0.0.1:6379> ttl Webuser:Tmp
(integer) 594
redis 127.0.0.1:6379> ttl Webuser:Tmp
(integer) 593
Il existe d’autres commandes pour le type simple clé-valeur comme MSET, INCR, DECR, APPEND ou STRLEN…
Une clé de type String peut stocker un objet volumineux comme un JPEG mais ce n’est pas le cas d’usage recommandé. Vous pouvez y mettre jusqu’à 512MB mais honnêtement, stockez vos images sur S3 et ne conservez que l’URL sur Redis.
Les différentes structures de données
Redis est particulièrement intéressant car il propose des structures de données comme les Lists, les Sets ou les Hashs. Rien à voir avec Java ou Scala, il s’agit bien ici de structures de données.
Les LISTs
Les listes sur Redis sont simplement des listes de String. L’ordre d’insertion est conservé. On retrouve la complexité d’une liste classique. Vous pouvez ajouter un élément au début ou à la fin avec un appel de complexité O(1). Une liste peut contenir jusqu’à 232 éléments (plus de 4 milliards).
La force des LISTs est que le temps d’insertion est constant. C’est très pratique si vous souhaitez modéliser par exemple des listes finies comme « les 5 derniers visiteurs de mon site Web ». Il suffit de combiner LPUSH pour ajouter le nom du visiteur, puis LTRIM (qui a une complexité plus importante de type O(N)) pour couper la liste et ne conserver que 5 éléments.
Tout d’abord j’ajoute 10 visiteurs dans ma liste. L’ordre d’insertion est le moment où la personne visite le site.
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:1
(integer) 1
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:2
(integer) 2
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:Temp
(integer) 3
redis 127.0.0.1:6379> LRANGE LastWebVisitors 0 -1
1) "Webuser:Temp"
2) "Webuser:2"
3) "Webuser:1"
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:2
(integer) 4
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:9
(integer) 5
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:1
(integer) 6
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:4
(integer) 7
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:5
(integer) 8
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:87
(integer) 9
redis 127.0.0.1:6379> LPUSH LastWebVisitors Webuser:3
(integer) 10
Voyons maintenant le contenu de la liste LastWebVisitors, puis ensuite coupons la liste afin de ne garder que les 5 visiteurs les plus récents :
redis 127.0.0.1:6379> LRANGE LastWebVisitors 0 -1
1) "Webuser:3"
2) "Webuser:87"
3) "Webuser:5"
4) "Webuser:4"
5) "Webuser:1"
6) "Webuser:9"
7) "Webuser:2"
8) "Webuser:Temp"
9) "Webuser:2"
10) "Webuser:1"
redis 127.0.0.1:6379> LTRIM LastWebVisitors 0 5
OK
redis 127.0.0.1:6379> LRANGE LastWebVisitors 0 -1
1) "Webuser:3"
2) "Webuser:87"
3) "Webuser:5"
4) "Webuser:4"
5) "Webuser:1"
6) "Webuser:9"
Afin de bien comprendre Redis et d’utiliser au mieux chaque structure, la documentation indique la complexité de chaque appel. Ainsi LPUSH ou RPUSH sont des appels très rapides, avec une complexité de type O(1). En fait, le temps d’insertion n’augmente pas, que la liste contienne 10 ou 100 000 éléments. Redis effectue en fait une copie vers une nouvelle liste en plaçant votre élément au début ou à la fin. Par contre la commande LTRIM a une complexité de type O(N). Elle sera de plus en plus lente sur une liste très importante.
Enfin si vous vous posez la question « est-ce que Webuser:5 est dans les 5 derniers visiteurs du site » alors la liste n’est pas la bonne structure de données. Il faut utiliser un SET.
Les SETs
Les SETs sur Redis sont des collections non ordonnées de String. La complexité pour ajouter, retirer ou vérifier la présence d’une clé donnée est constant, O(1), ce qui fait que les SET sont des indexes particulièrement efficaces. Chaque clé est unique, et si vous insérez une nouvelle valeur avec la même clé, vous allez simplement écraser l’ancienne valeur. Je m’en sers comme des indexes, avec quelques pouvoirs magiques que je vais vous montrer dans quelques instants.
Tout d’abord, nous allons définir un SET des utilisateurs qui possèdent un email GMail :
redis 127.0.0.1:6379> SADD Webuser:HasGMail Webuser:3
(integer) 1
redis 127.0.0.1:6379> SADD Webuser:HasGMail Webuser:2
(integer) 1
redis 127.0.0.1:6379> SADD Webuser:HasGMail Webuser:5
(integer) 1
redis 127.0.0.1:6379> SMEMBERS Webuser:HasGMail
1) "Webuser:2"
2) "Webuser:5"
3) "Webuser:3"
Ensuite définissons un SET pour les utilisateurs qui sont Français :
redis 127.0.0.1:6379> SADD Webuser:IsFrench Webuser:5
(integer) 1
redis 127.0.0.1:6379> SADD Webuser:IsFrench Webuser:7
(integer) 1
redis 127.0.0.1:6379> SADD Webuser:IsFrench Webuser:9
(integer) 1
redis 127.0.0.1:6379> SADD Webuser:IsFrench Webuser:2
(integer) 1
redis 127.0.0.1:6379> SMEMBERS Webuser:IsFrench
1) "Webuser:2"
2) "Webuser:9"
3) "Webuser:7"
4) "Webuser:5"
Les SET permettent d’effectuer des opérations directement sur Redis, ce qui permet de lancer des croisements de données particulièrement efficace. Dis autrement, vous pouvez faire des jointures entre vos ensembles afin de ne récupérer que l’INTERsection ou la DIFFérence entre 2 ou plusieurs SETs :
# Donne moi les utilisateurs Français avec GMail
redis 127.0.0.1:6379> SINTER Webuser:IsFrench Webuser:HasGMail
1) "Webuser:2"
2) "Webuser:5"
# Donne moi la différence entre le premier SET et les autres SET spécifiés ici
redis 127.0.0.1:6379> SDIFF Webuser:IsFrench Webuser:HasGMail
1) "Webuser:9"
2) "Webuser:7"
SINTER s’applique à l’ensemble des SET. SDIFF part du premier SET et retire ce qu’il ne trouve pas dans les SETs passés en argument.
Enfin encore plus intéressant, vous pouvez stocker le résultat de ces appels afin, vous l’aurez compris, de créer des indexes sur Redis. Le tout sans remonter dans votre code une ligne de données. C’est l’un des moyens que nous utilisons pour classer par origine et par catégorie nos deals sur le site.
redis 127.0.0.1:6379> SINTERSTORE Webuser:FrenchWithGMail Webuser:IsFrench Webuser:HasGMail
(integer) 2
redis 127.0.0.1:6379> SMEMBERS Webuser:FrenchWithGMail
1) "Webuser:2"
2) "Webuser:5"
Les Hashs
Les Hashs sur Redis sont de purs Map de String. Naturellement, c’est la structure qui semble le plus adapté pour représenter un objet comme un utilisateur de votre site Web.
redis 127.0.0.1:6379> HSET Webuser:Nicolas email toto[AT]zaptravel.com
(integer) 1
redis 127.0.0.1:6379> HSET Webuser:Nicolas lastName Martignole
(integer) 1
redis 127.0.0.1:6379> HSET Webuser:Nicolas firstName Nicolas
(integer) 1
redis 127.0.0.1:6379> HGETALL Webuser:Nicolas
1) "email"
2) "toto[AT]zaptravel.com"
3) "lastName"
4) "Martignole"
5) "firstName"
6) "Nicolas"
redis 127.0.0.1:6379> HGET Webuser:Nicolas firstName
"Nicolas"
Cependant mon expérience est que ce stockage est assez couteux. Nous avons fait le choix, en se basant sur notre expérience et nos besoins en codant l’application, de stocker plutôt du JSON. Evidemment nous perdons alors la possibilité d’accéder à chaque champ de manière unitaire. Nous pourrions dupliquer les données, mais rappelez-vous, Redis est une base en mémoire. Il est important d’optimiser la taille de vos structures afin de limiter la consommation mémoire.
Finalement si vous regardez notre base, vous verriez plutôt quelque chose comme ceci :
redis> TYPE Webuser:UUID:1234567890
string
redis> GET Webuser:UUID:1234567890
"{\"uuid\":\"1234567890\",
\"email\":\"john.doe[AT]gmail.com\",
\"name\":\"John\",
\"facebookId\":\"123456\",
\"password\":\"crypted_password\",
\"originCity\":\"from-paris\",
\"segment\":\"comfort\",
\"cdate\":1363899144657}"
En effet, nous stockons ici directement l’utilisateur sous la forme d’un objet JSON. Et c’est parfait car je vous montrerez prochainement comment coder une petite application en Scala pour aller chercher ces données sur votre serveur Redis.
Update 2023 : Redis propose le support natif de JSON désormais. Voir https://redis.io/docs/latest/develop/data-types/json/
Les SortedSet (ou ZSET)
Enfin dernière structure, mais pas des moindres, les ZSet. Il s’agit de SET, avec la possibilité d’attacher un score à chaque valeur. Le score doit forcément être une valeur numérique. Cela peut représenter un prix ou par exemple un timestamp unix.
Les ZSet sont utilisés comme des indexes, et sont très pratiques lorsque par exemple vous voulez montrer les 10 deals les moins chers ou les mieux notés sur votre site… sur 900 000. Vraiment c’est ultra rapide, très pratique pour faire des tableaux de scores ou des outils pour du data mining.
Je vais vous donner un cas d’usage : classer par prix des voyages. Je vais créer un SET de voyages en spécifiant à chaque fois le prix en euros.
redis rio.zaptravel.com:6379> ZADD DealsFranceByPrice 59 Trip:Lyon
(integer) 1
redis rio.zaptravel.com:6379> ZADD DealsFranceByPrice 259 Trip:Venise
(integer) 1
redis rio.zaptravel.com:6379> ZADD DealsFranceByPrice 130 Trip:Bordeaux
(integer) 1
redis rio.zaptravel.com:6379> ZADD DealsFranceByPrice 990 Trip:Paris
(integer) 1
Tout d’abord voyons quel est le voyage le moins cher dans cette collection :
redis rio.zaptravel.com:6379> ZRANGE DealsFranceByPrice 0 0
1) "Trip:Lyon"
Et maintenant le voyage le plus cher, en me donnant aussi le prix stocké ?
redis rio.zaptravel.com:6379> ZREVRANGE DealsFranceByPrice 0 0 WITHSCORES
1) "Trip:Paris"
2) "990"
Donne moi les voyages dont le prix est inférieur à 200 EUR, du voyage le plus cher au moins cher :
redis rio.zaptravel.com:6379> ZREVRANGEBYSCORE DealsFranceByPrice 200 0 WITHSCORES
1) "Trip:Bordeaux"
2) "130"
3) "Trip:Lyon"
4) "59"
Imaginons que vous ayez beaucoup de voyage… Comment retrouver uniquement les 10 voyages les moins chers en dessous de 200 EUR, par ordre de prix croissant ?
redis rio.zaptravel.com:6379> ZRANGEBYSCORE DealsFranceByPrice 0 200 WITHSCORES LIMIT 0 10
1) "Trip:Lyon"
2) "59"
3) "Trip:Bordeaux"
4) "130"
ZRANGEBYSCORE charge les éléments dont le score est compris entre 0 et 200, en affichant le score. Enfin LIMIT 0 10 est utile lorsque vous souhaitez paginer vos données. Ici je ne demande que 10 éléments en débutant à l’index 0. C’est assez similaire à ce que l’on peut faire en SQL.
Les ZSets sont très pratiques comme indexes de calculs. ZRANK permet aussi de trouver à quel rang se trouve une clé donnée. Enfin la commande qui tue c’est ZINTERSTORE. Cette clé permet de stocker l’union de plusieurs ensembles et d’effectuer des calculs comme la somme, la moyenne, la recherche de la valeur max, bref de vous créer de superbes indexes aux petits oignons pour ranger vos données.
Exemples d’utilisations de Redis
Alors à quoi peut servir Redis ?
J’ai découvert plusieurs cas d’usages. Tout d’abord pour du prototypage. Plutôt que de partir avec une base MySQL, essayez et vous verrez que c’est ultra-simple. Très pratique pour coder une application pour générer 1478 Badges ainsi que les QRCodes pour une certaine conférence il y a quelques jours.
Ensuite Redis est un cache ultra redoutable. Plutôt que d’utiliser EHCache dans mon application Web, je préfère m’appuyer sur Redis. Tout d’abord il est déjà en mémoire. Ensuite je peux optimiser mes données et effectuer mes traitements directement sur Redis. Enfin il tourne comme un serveur. Je peux donc placer en frontal 10 serveurs Webs afin d’utiliser le même espace de données sans soucis.
Redis est aussi pratique lorsque vous souhaitez gérer une queue asynchrone de message. Oui l’équivalent d’un Pub/Sub avec du JMS. Mais c’est plus simple et bien suffisant dans beaucoup de cas.
Quoi d’autre ? Le modèle de programmation est simple. En tant que développeur, j’ai aussi facilement un clone de la prod en temps réel sur ma machine. C’est un luxe énorme, qui permet de travailler en condition de prod. Bon, je l’avoue, j’ai aussi 16GB sur mon ordinateur. Mais cela me permet de travailler vraiment sur de « vraies données ».
Mais tout n’est pas si rose
Redis demande un temps pour bien comprendre ses structures. Croyez-moi, au début on cherche un peu et il manque un peu d’exemples « de la vraie vie » pour bien structurer son modèle. Ensuite Redis étant une pure base en mémoire, n’oubliez pas d’activer soit la sauvegarde sur disque, soir un slave pour sauver vos données. Sinon dès que le serveur s’arrêtera, vous n’aurez plus rien. C’est bête, mais ça, c’est du vécu.
Par rapport à MongoDB, Redis vous demandera plus de travails. Ici pas d’indexes pour booster vos recherches. Ce sera à vous d’y aller et de coder vos structures. C’est plus long qu’avec un BTree sur MySQL ou avec MongoDB. Mais en même temps, cela force à bien structurer son application.
Enfin Redis est mono-core. Sur mon superbe i7, il ne tourne que sur un seul core. Si vous voulez plus de puissance (mais j’avoue que je n’ai jamais eu de soucis de performances avec Redis), vous pouvez démarrer plusieurs serveurs sur la même machine, sur des ports différents.
Par défaut, votre base n’est pas sécurisée. Un client peut se connecter dessus et lancer un FLUSHDB, qui videra les données. Il faut activer soit la protection par clé, soit simplement faire en sorte que vos serveurs Redis ne soient pas sur Internet.
Qu’y-a-t-il de « pas si cool » ? Pas de réplication de données entre serveurs physiques par défaut. Si vous perdez votre machine sur Amazon, un paquet de kleenex sera votre seul consolation. Mais heureusement il y a la réplication. Il suffit de configurer d’autres machines en SLAVE dans d’autres zones, ce qui suffit à garantir que vos données sont bien réparties. Enfin nous utilisons aussi Amazon S3 pour y stocker les DUMP de Redis chaque heure. Ceci nous permet de conserver des archives de nos données. Je peux récupérer un dump du mois de février et le monter sur mon serveur Redis en local pour travailler. Je ne vous cache pas que c’est assez pratique.
Conclusion
Pour terminer, si vous n’avez pas eu le courage d’installer Redis, prenez au moins 10mn pour tester Redis en direct sur Try Redis.IO. Vous pourrez revoir ce que j’ai présenté dans cet article.
Redis n’a rien à voir avec la JVM et le monde Java. Et c’est peut-être bien quelque part. Vous pouvez coller un client Ruby, PHP ou même un script Shell pour jouer des commandes et préparer votre base. Couplé à un moteur ElasticSearch, vous avez, à mon avis, quelque chose d’assez puissant.
Prochain article : comment utiliser Jedis ou Scala pour accéder à Redis.
A bientôt
Très bon article pour bien débuter avec Redis, je partage 🙂
Super introduction !
Intéressé à l’occasion de voir un exemple d’interaction entre elastic search et redis…
Christophe.
Sur la complexité dans le doc, c’est juste ultime 🙂 Toutes les documentations de BDD devraient copier celle de Redis ^^
Sinon :
« Ainsi LPUSH ou RPUSH sont des appels très rapides, avec une complexité de type O(1).Redis effectue en fait une copie vers une nouvelle liste en plaçant votre élément au début ou à la fin »
=> Tu es sûr de ça ? Intuitivement j’aurai pensé que s’il fait une copie de N élément, c’est du O(n). Intuitivement toujours, je pense qu’il gère des listes chainées, donc sans copie de liste pour LPUSH et RPUSH, mais je n’ai pas de source 🙂
Redis est par définition multi-threadé mais mono-coeurs.
Il y a une coquille là ? cf le chapitre « Single threaded nature of Redis » de la doc (http://redis.io/topics/latency)
Approche claire, nette & précise.
Il manque peut-être un benchmark au niveau des temps d’accès vs les DB SQL.
@NicRemond : erreur corrigée, merci !
Super article sur ce système clef/valeur qui mérite réellement d’être connu. Le fait d’utiliser exclusivement ce backend sur ZapTravel est assez impressionnant !