57

REX Storm Redis

Embed Size (px)

DESCRIPTION

Retour d'expérience sur l'utilisation de Storm et Redis sur le projet twitter-foot pour l'Agence France Presse

Citation preview

Page 1: REX Storm Redis
Page 2: REX Storm Redis

REXSTORM REDIS

Page 3: REX Storm Redis

• Les besoins du projet AFP twitter-foot

• Présentation de Redis

• Manipuler des tweets avec Storm

• Implémenter des fenêtres glissantes

• Testabilité du cluster

• Monitoring et supervision

• Débogage et bonnes pratiques

Page 4: REX Storm Redis

• Plus de 7000 comptes twitter référencés par l’AFP

• 5 ligues de football suivies

• Jusqu’à 170 tweets par seconde

• Recherche de tendances sur les hashtags

• Classements de popularité de joueurs / équipes et panelistes

• Des timelines de tweets par ligue, par équipe et par matches en live

Page 5: REX Storm Redis
Page 6: REX Storm Redis

Redis

Twitter Feeder

Serveur REST pour front-end

Serveur workersStorm

Serveur Zookeeper+Storm nimbus

Page 7: REX Storm Redis

• Utilisation de Storm pour le tri des tweets reçus, et la recherche de mots clé

• Utilisation de Redis comme queue pour le flux d’entrée

• Utilisation de Redis pour la gestion et le stockage des timelines

• Serveur Web Services REST (Jetty)

Cluster de 7 serveurs en toutpour le backend

Page 8: REX Storm Redis

REDIS

Page 9: REX Storm Redis

• Datastore de type Key / Value

• Données en RAM uniquement

• Implémentation en C ANSI

• Monothreadé

• Support de publish / subscribe

• Communication sur TCP avec protocole spécifique

• Nombreux clients disponibles en divers langages

• Sponsorisé par Pivotal

Page 10: REX Storm Redis

Parmi les applications reposant sur redis on retrouve: StackOverflow, Github, Pinterest, Flickr, Snapchat… et Twitter!

Redis est notamment utile pour

• Améliorer les performances d'une base de données (MySQL, MongoDB…)

• Gérer finement un cache applicatif

• Traiter des statistiques et des classements

• Servir de Message Broker et gérer des notifications entre applications

Redis est un vrai couteau suisse!

Page 11: REX Storm Redis

"Bad programmers worry about the code. Good programmers worry about data structures and their relationships." L. Torvalds

Structures disponibles• Les sets

• Les listes

• Les hashes

• Les strings

• Les bitmaps

• Les HyperLogLogs

• Les Sorted Sets

Page 12: REX Storm Redis

• Notion de score par élément (stocké en tant que "double" soit 64 bits mais 53 bits significatifs seulement)

• Récupération d’un ensemble d’éléments par leurs positions ou leurs scores

• Implémentation via des skip-lists et des hashsets assurant des performances élevées

• Utilisation documentée permettant notamment de calculer avec précision le coût des requêtes effectuées

• La performance élevée implique néanmoins une occupation mémoire supérieure aux structures classiques

Page 13: REX Storm Redis

• ZADD ajoute un élément à un ZSET avec un score• ZINCRBY incrémente le score d'une valeur choisie• ZRANGE récupère une plage d'éléments par leur index défini par leur score

(plus petit au plus grand): idéal pour un classement (les 10 meilleurs par exemple)

• ZRANGEBYSCORE récupère une plage d'éléments dans un intervalle de scores (score entre 5 et 10…)

Page 14: REX Storm Redis

redis> ZADD myzset 1 "one"

(integer) 1

redis> ZADD myzset 2 "two"

(integer) 1

redis> ZINCRBY myzset 2 "one"

"3"

redis> ZRANGE myzset 0 -1 WITHSCORES

1) "two"

2) "2"

3) "one"

4) "3"

redis> ZADD myzset 1 "one"

(integer) 1

redis> ZADD myzset 2 "two"

(integer) 1

redis> ZADD myzset 3 "three"

(integer) 1

redis> ZRANGEBYSCORE myzset -inf +inf

1) "one"

2) "two"

3) "three"

redis> ZRANGEBYSCORE myzset 1 2

1)"one"

2) "two"

Page 15: REX Storm Redis

• Utilisation de tweets comme valeurs dans un ZSET et utilisation du Tweet ID comme score

• Timelines de tweet ordonnancées par tweetid: chronologie respectée

• Plus récent: tweet id le plus élevé (snowflake le garantit)

• Utilisation de tweets comme valeurs dans un ZSET et du nombre de retweets comme score

• Classement des tweets les plus retweetés

Page 16: REX Storm Redis

22:04:41:524652515665915905:nicolas_vilas:RTcount=0:Une action de David Luiz qu'on risque de revoir... en boucle #APOELPSGprofiles=["JRNL"] teams=["NEUTRAL"] leagues=["FRAL1"]

22:04:33:524652479569752065:NikoB19:RTcount=0:Tous les matchs sur Bein (sauf Porto - Bilbao) sont joués, je file à la douche en espérant un but parisien. profiles=["BLOG"] teams=["LENS"] leagues=["FRAL1"]

22:04:23:524652438729416704:PSG_inside:RTcount=31:57' Sauvetage de @DavidLuiz_4 sur la ligne Parisienne ! Corner pour l'@apoelfcofficial. #APOELPSG profiles=["TEAM"] teams=["PSG"] leagues=["FRAL1"]

22:04:11:524652387664158720:Gibney_A:RTcount=1:WOW. So close to a goal. David Luiz clears a header off his own line. profiles=["JRNL"] teams=["LILL"] leagues=["FRAL1"]

22:04:08:524652374439493632:RemDenjean:RTcount=0:#Maxwell est vraiment un très grand footballeur: professionnel, classe, talentueux, combattif... L'une des meilleures recrues du PSG 2.0! profiles=["TEAM"] teams=["TOUL"] leagues=["FRAL1"]

Score524652515665915905

Score524652479569752065

Score524652438729416704

Score524652387664158720

Score524652374439493632

ZSET "timeline"Les valeurs contiennent le JSONLes scores sont les tweet ids

Page 17: REX Storm Redis

Les opérations sur ZSET sont majoritairement en O(log(N))

• ZSCORE est en O(1)

• ZADD est en O(log(N)) avec N le nombre d'éléments dans le ZSET

• ZINCRBY est en O(log(N)) avec N le nombre d'éléments dans le ZSET

• ZRANGE est en O(log(N) + M) avec N le nombre d'éléments dans le ZSET et M le nombre d'éléments retournés

Page 18: REX Storm Redis

• Clusterisation en beta ou à faire manuellement, difficile à réaliser

• Pas de "rollbacks" de transactions

• La persistance des données a un impact sur les performances dans les deux modes proposés

• Le mode par défaut de persistance peut perdre des données en cas de crash

• Tout est en mémoire RAM, attention aux leaks et aux Out-of-memory!

• Pas de version windows officielle (mais il existe un port)

• Intégration à Java minimale mais suffisante (Jedis, Spring-redis)

Page 19: REX Storm Redis

• Les tweets ids sont ordonnancés chronologiquement (snowflake), les timelinessont faciles à gérer via des Sorted Set

• Utilisation du tweet id comme score pour les timelines

• Utilisation du tweet id comme valeur pour les autres classements (retweets, mots-clé …)

• Performances élevées en accès aux données et en débit

• Un datastore à la complexité modérée et au coût d'entrée faible

• Intégration facile avec Storm

• Perdre quelques tweets n'est pas (si) important

Page 20: REX Storm Redis

STORM

Page 21: REX Storm Redis

1. Utilisation de la connexion hosebird vers twitter alimentant une queue redis

2. Récupération des messages twitter depuis Redis via un Spout dédié

3. Définition de divers streams en Storm pour le traitement des tweets

4. Stockage des résultats dans Redis

Twitter-feederHosebird

Redis Spout Storm "Raw" Bolt Storm

AlimentationQueue

Dirty check queue

Emission des tuplesTwitter

Création des streams

Page 22: REX Storm Redis

Redis

Twitter Feeder

Serveur REST pour front-end

Serveur workersStorm

Serveur Zookeeper+Storm nimbus

Page 23: REX Storm Redis

• Recherche de mots-clé divers• Classement de joueurs via liste de mots clé

• Classement d'équipes

• Classements des hashtags populaires

• Classements des tweets les plus retweetés

• Classements des comptes twitter les plus actifs

• Recherche de médias: images / vidéos

• Croisement avec des données journalistiques du bureau des sports

Page 24: REX Storm Redis

• Configuration stockée en JSON dans Redis

• Spouts de configuration sur divers thèmes• Dirty check de clés de configuration sur Redis

• Envoi de la nouvelle configuration en tant que tuple si changement détecté

Redis Spout de configuration

Bolts abonnés au Streamde configuration

Dirty checkde la configuration

Serveur manager des configurations

Changement de la configurationdans redis

Page 25: REX Storm Redis
Page 26: REX Storm Redis
Page 27: REX Storm Redis

Pour améliorer les performances, plusieurs solutions:

• Augmenter le nombre d'Executors• Augmente le nombre de threads s'exécutant sur le Bolt / Spout concerné dans le cluster

• Limitation par le nombre de CPU disponibles sur le cluster avec / sans Hyperthreading

• Augmenter le nombre de Tasks• Revient à augmenter le nombre d'instances du Bolt / Spout concerné dans le cluster

• Changer le design applicatif / algorithmes utilisés

Page 28: REX Storm Redis

Le livrable de Storm est simple: Jar contenant la topologie• Peu lié aux spécificités du runtime du cluster Storm

• Corriger une erreur de design interne est donc plus facile lors des montées de version

• Le refactoring est donc encouragé

La difficulté dans l'usage de Storm se trouve autant dans le développement que dans l'administration du cluster. Plusieurs options (cumulables):

• Soyez / devenez DevOps

• Chouchoutez votre administrateur système / réseau

• Optez pour une solution Cloud

Page 29: REX Storm Redis

Fenêtres glissantes

Page 30: REX Storm Redis

• Parcours d'un itérable sur un nombre fixe de n éléments

• Cet itérable est peuplé de nouvelles données au fur et à mesure

• Eviction des données trop anciennes

• Utilisation possible pour le calcul de débits en "live"

• Bande passante utilisée

• Occurrence de mots clé

Page 31: REX Storm Redis

• Choix d'une durée pour la fenêtre• les 15 dernières minutes

• Choix d'une fréquence de calcul• MAJ toutes les 5 secondes

• Comptage du nombre de tweets dans une structure adaptée• Rolling buffers, zsets…

• Le résultat donne un quotient de tweets par seconde• débit "live" de 35 tweets par seconde

basé sur le nombre de tweets reçus des 15 dernières minutes,recalculé toutes les 5 secondes

Page 32: REX Storm Redis

Storm peut servir à calculer des fenêtres glissantes (Sliding Window)• Chaque donnée possède un timestamp qui permet de calculer son éligibilité aux

fenêtres glissantes

• Un buffer en mémoire représentant la fenêtre glissante compte les occurrences d'une donnée choisie sur une période donnée

• Une tâche calcule le débit à intervalle régulier

Deux outils sont fournis et documentés avec Storm pour cet effet• Les Tick tuples

• Les rolling buffers

Page 33: REX Storm Redis
Page 34: REX Storm Redis

• Un Bolt de type "Map" émet des éléments individuellement

• Un Bolt de type "Reduce" s'abonne au Bolt "Map" en field grouping• Stockage dans un buffer in-memory des éléments reçus et du nombre de leurs occurrences

• Emission d'un Tuple "résumé" périodiquement grâce aux Tick Tuples

• Un Bolt de type "Ranker" récupère les résultats de tous les types "Reduce" et calcule le résultat

Page 35: REX Storm Redis

Pour réaliser une Sliding Window en Redis, il suffit de stocker les données brutes de comptage en tant que ZSET sur une unité de temps choisie (minute, heure, jour…)

Quand on désire calculer les valeurs finales, il suffit de réaliser un ZUNION qui additionne les clés ZSET choisies en produisant un ZSET des résultats

Ronaldo:1

Ribery:2

Messi:1 Ronaldo:3

Messi:2

Ronaldo:4

Messi:3

Ribery:2

players:23h00 players:23h01 players:23h02 players:current-ranking

ZUNION des 3 dernières minutesExécution toutes les minutes

Page 36: REX Storm Redis

Implémentation Storm• Permet de faire du Map-Reduce efficacement

• Nettoyage des buffers auto-géré par les structures fournies

• Utilise la RAM JVM, ce qui peut donner un Out-of-memory détruisant le Worker et pouvant perdre les données du buffer en cours

Implémentation Redis• Données brutes dans Redis: facilement auditable

• Pas de pertes de buffers lors d'un crash de worker Storm

• Utilise la RAM Redis, attention au Out-of-memory

• Nettoyage des valeurs dans Redis manuel

• Ajoute de la charge sur Redis

Page 37: REX Storm Redis

Testabilité

Page 38: REX Storm Redis

• Technique permettant de valider une fonctionnalité par l'exécution de tests (avec succès)

• S'apparente à un test de type "boîte noire" en mode End-to-End

• Il est possible d'intégrer ce mode de validation dans un process Agile

Page 39: REX Storm Redis

• Framework de tests permettant la mise en place de tests d'acceptance

• Ecrit originellement en Ruby mais porté en Java (entre autres)

• Utilisation de Domain Specific Language (DSL) pour décrire les tests

• Fonctionne avec JUnit, Mockito

Page 40: REX Storm Redis

Feature: Top N of players in the global timeline.

Scenario Outline: : Player appears in the tweet.

Given a panelist for the league "<League>"

And the player keyword is "<Keyword>"

When the panelist tweets "<Tweet>"

Then the global player counter of "<Keyword>" is 1

Examples:

| League | Keyword | Tweet |

| FRAL1 | Lucas Deaux | Le milieu Lucas Deaux est la révélation de cette année |

| ENGL1 | Zat Knight | The best central defender is Zat Knight |

Scenario: Player appears in the beginning of the tweet.

Given a panelist

And the player keyword is "Djordjevic"

When the panelist tweets "Djordjevic ne restera malheureusement pas nantais l'an prochain"

Then the global player counter of "Djordjevic" is 1

Page 41: REX Storm Redis

• Cucumber est appelé depuis un Test JUnit (Runner spécifique)

• La feature Cucumber est parsée

• Une classe "StepDefs" Java est appelée par Cucumber

• Cucumber matche les phrases du scénario à des méthodes Java• Via des annotations: @Given @When @Then

• Utilisation de RegExp: "^the global player counter of \"([^\"]*)\" is (\\d+)$"

• Cucumber exécute les méthodes et injecte les paramètres définis dans le scénario

• JUnit donne le résultat du test

Page 42: REX Storm Redis

Le déroulement d'un test donne1. Une phase de préparation démarre la topologie et initialise les données dans le Redis de

test

2. L'exécution du scénario de test simule l'arrivée d'un tweet forgé dans Redis

3. L'application Storm dans le cluster local de test traite le tweet et stocke le résultat dans le Redis de test

4. L'assertion définie dans Cucumber est exécutée et donne un reporting, par exemple un polling sur Redis vérifiant la valeur d'un compteur

5. Si la feature Cucumber contient d'autres scénarios ils sont exécutés 1 à 1

6. La phase terminale du test stoppe le cluster et nettoie le redis de test

La topologie de test n'est donc pas redémarrée à chaque test ("scenario") pour diminuer le temps d'exécution

Page 43: REX Storm Redis

Il est souhaitable d'avoir des tests End-to-End dans une application Storm pour• Faciliter le débogage

• Documenter les fonctionnalités

• Eviter les régressions

Néanmoins les tests sont coûteux à maintenir au fil des évolutions de l'applicatif• Les tests avec mocks complexes sont "fragiles"

• La non maintenance des tests signifie leurs morts

• Sans implication d'un membre de la partie métier, cela ne restera qu'un outil de développeur

Page 44: REX Storm Redis

MonitoringSupervision

Page 45: REX Storm Redis

• Serveur Zookeeper de coordination

• Storm-nimbus

• Storm-supervisors

• Storm-workers

• Redis

• Serveurs REST pour le front-end

Page 46: REX Storm Redis

• Création d’artifacts zip via Maven pour chaque serveur

• Scripts pour toutes les tâches courantes (MAJ configuration, restart, etc)

Page 47: REX Storm Redis

• Scripts de redémarrage de process

• Supervision du CPU et de la RAM

• DSL avancé de configuration

check process redis-serverwith pidfile "/var/run/redis.pid"start program = "/etc/init.d/redis-server start"stop program = "/etc/init.d/redis-server stop"if 2 restarts within 3 cycles then timeoutif totalmem > 7000 Mb then alertif cpu usage > 95% for 3 cycles then restartif failed host 127.0.0.1 port 6379 then restartif 5 restarts within 5 cycles then timeout

Page 48: REX Storm Redis
Page 49: REX Storm Redis

Redis-rdb-tools est un parser de dump Redis de type "RDB"• Permet l'audit des clés d'une instance en mode "offline"

• Calcul approximatif de l'espace occupé de chaque clé de l'instance

Page 50: REX Storm Redis

Redmon et RedisLive sont des outils de monitoring de Redis en live• Accès au slowlog (requêtes les plus longues)

• Informations sur la mémoire (occupation, fragmentation)

• Aperçu des structures de données utilisées dans l'instance

Page 51: REX Storm Redis

Debug modeBest practices

Page 52: REX Storm Redis

L'architecture Storm + Redis est très distribuée, par conséquent fixer (trouver) un bug peut devenir un vrai challenge

Pour éviter un coût de maintenance élevé et s'assurer la pérennité de l'application, il faut éviter de cumuler les problématiques au même endroit

L'outil Sonar est un moyen utile de surveiller le projet

Page 53: REX Storm Redis

• Séparer l'action (Bolt d'action) de la condition (Bolt de contrôle)

• Séparer l'insertion de résultat dans Redis de son nettoyage

• Utiliser des design patterns: Strategy, Chain of Responsibility…

Une séparation plus extrême consiste à définir plusieurs topologies• Communication entre topologies assurées par un élément externe (Redis par exemple)

• Audit facilité des problèmes

• Meilleure testabilité

• Meilleure maintenabilité

• Meilleure robustesse

• Nécessite plus de workers Storm (1 worker ne sert qu'une seule topologie)

• Permet de faire de la pseudo QoS sur des topologies

Page 54: REX Storm Redis

• Tracer les tuples naviguant dans une topologie est utile• Débogage plus facile

• Audit de performances

• Ajouter un objet "espion" dans chaque stream peut servir à cet effet

• Ajouter le nom de chaque Bolt traversé

• Chronométrer le temps passé dans chaque Bolt ou méthode de Bolt

• Garder une trace de certains tests métier

• Certains bugs sont difficiles à reproduire avec Storm, aussi, avoir de bons logs peut grandement aider aux fixes

Page 55: REX Storm Redis

• Redis est un stockage temporaire dans notre modélisation

• Chaque entrée doit être nettoyée à un moment donné

• Il est important d'être rigoureux dans le référencement de clés afin d'éviter les leaks et de faciliter le débogage

• Le format des données insérées est aussi important, l'utilisation de standards peut grandement aider: json-schema, XSD, DTD…

• Une bonne méthode est de séparer les tâches d'insertion des tâches de suppression

• Bolts / Spouts différents

• Topologies différentes

Page 56: REX Storm Redis

• Redis supporte Lua nativement

• Comme Redis est monothreadé, aucune requête redis n'est effectuée pendant l'exécution d'un script Lua en parallèle

• Un script Lua est donc atomique sur une instance Redis

• Lua permet d'éviter des round-trips réseau

• Possibilité d'utiliser la librairie cjson en Lua ainsi que MSGPACK qui permet de compresser les données JSON

Page 57: REX Storm Redis

Questions