Résultats:

Bravo à @lucasdicioccio !

Le gagnant @lucasdicioccio, a eu la meilleure note avec 18/20 et a donc remporté le Nouvel Ipad !

Voici le protocole de test qui a servi à déterminer le gagnant. Les notes s'étalent de 18/20 à 10/20 dont 50% à 15 et au-delà.

Lucas avait la solution la plus compliquée (à base de ØMQ) mais également la plus précise par rapport aux règles. A noter l'excellente qualité des participations, redis a fait l'unanimité chez les participants mais Event Machine et ØMQ ont été de la partie.

Le détail des notes sera envoyé aux participants et nous sommes à leur disposition pour toute explication.

Solution @lucasdicioccio » Environnement et protocole de test »

Merci encore à tous les participants, et rendez-vous très vite pour la prochaine édition du #dimelocontest !

Un défi en Ruby !

Pour la 2e édition du Dimelo Contest, nous vous proposons de coder un middleware Rack pour:

  • déterminer les urls accédées via Rack,
  • calculer le nombre approximatif de visiteurs uniques,
  • et cela en temps réel, agrégé sur les 5 dernières minutes.

Ce middleware rack doit pouvoir fonctionner sur tous les thread/process Rack utilisant le middleware sur un même reseau. Vous pouvez consulter les détails dans la section suivante ainsi que les critères d'évaluation.

Le nouvel iPad à gagner !

Peu de règles !

Tout rubyiste peut participer ! Pour gagner, il faut :

  • fournir un programme qui fonctionne et respecte les contraintes
  • avoir un algorithme performant, scalable au niveau des données et en fonction du trafic, et le plus précis possible ...
  • 1 programme par personne - pas de programme en doublon
  • nous autoriser à publier votre solution ici (ou sur github) en cas de victoire
  • rendre sa solution avant le 11 avril 2012 à midi CEST

Pour toute question, contactez-nous sur Twitter @dimelo, ou publier un tweeds avec le hashtag #dimelocontest.

Sinon, rendez-vous en section contact.

Détails fonctionnels

Support Multiprocess

Le middleware agrégera l'ensemble des données des process/thread rack du réseau utilisant le middleware.
Cette agrégation peut se faire au niveau du stockage s'il y en a, ou de toute autre manière laissée à la libre appréciation de l'implémenteur.

Cette agrégation se fera par défaut entre tous les process rack mais il est possible de positionner un paramètre env['rack.livetraffic_id'] au niveau de chaque requête pour n'agréger que sur les requêtes ayant cette id.

Informations agrégées

Le middleware rack permettra d'agréger sur une certain période l'information sur les données suivantes:

  • le nombre de requêtes sur la période,
  • le nombre de requêtes par seconde en moyenne sur la période,
  • les visiteurs uniques sur la période (l'algorithme tentera de prendre en compte les connexions "nattées"),
  • le nombre d'accès par hostname sur la période,
  • le nombre d'accès par hostname/path sur la période (c'est à dire les url sans les query string),
  • les url des 10 requêtes les plus lentes sur la période.

Période d'agrégation

Les données récupérées permettront de déterminer les informations demandées sur une période de 5 minutes glissantes aka les "dernières 5 minutes". Le résultat de cette agrégation n'a pas besoin d'être disponible sous forme de résultat dans la mémoire et/ou le stockage. Le client rack-top (cf section le client) peut les calculer quand il en a besoin.

L'implémentation devra faire au mieux pour ne pas être trop sensible à un éventuel décalage de temps entre les serveurs d'un même réseau.

Important Il n'est pas demandé de conserver d'historique des informations au-delà des 5 minutes, au contraire, un des critères de jugement sera la scalabilité au niveau du stockage s'il y en a, sur le/les daemons sinon. Si vous avez besoin de fournir un script de nettoyage mettez-le dans un script/clean, le script de nettoyage doit également scaler convenablement.

Le client : la lecture des données

Le middleware rack se charge de la récupération des données. Ces données sont lues à la demande par un client.

Le client est un simple script disponible à script/rack-top et s'exécutant avec un appel à ./script/rack-top <livetraffic_id>. livetraffic_id est un paramètre optionnel correspondant au paramètre env['rack.livetraffic_id'] qui permet d'avoir plusieurs silos pour gérer les statistiques de plusieurs applications Rack indépendantes.

Les temps seront donnés en ms et les moyennes seront arrondies à 1 décimale.

L'execution de ./script/rack-top renvoie un json répondant au format suivant:

        {
          "requests": 53,
          "rate": 10.5,
          "uniq_visitor": 4,
          "hostnames":  {
                          "mysite.com": { "total" => 50,
                                          "paths" => {
                                            "/foo": 40,
                                            "/bar": 10
                                          }
                                        },
                          "admin.mysite.com": { "total" => 3,
                                                "paths" => {
                                                  "/users" => 3
                                                }
                                              }
                        },
          "slow_requests":  [
                              { "http://mysite.com/foo?params1=slow": 10 },
                              { "http://mysite.com/bar": 9 },
                              { "http://mysite.com/bar": 8 },
                              { "http://mysite.com/bar": 8 },
                              { "http://mysite.com/bar": 8 },
                              { "http://mysite.com/bar": 7 },
                              { "http://mysite.com/bar": 7 },
                              { "http://mysite.com/bar": 7 },
                              { "http://admin.mysite.com/users?order=created_at": 6 },
                              { "http://admin.mysite.com/users?order=confirmed_at": 6 }
                            ]
        } 
      

Voici le détail des clés :

Clé Type Description
requests number Nombre de requêtes sur la période
rate number Requêtes par seconde en moyenne sur la période
uniq_visitor number Nombre de visiteurs uniques sur la période
hostnames Object L'object contient des clés correspondant aux hostnames. Chacune de ces clés à pour valeur un object qui contient deux clés: une clé total qui contient le nombre total de requête sur le hostname et une clé paths qui contient un autre object dont les clés sont les paths accèdés et en valeur le nombre de requête sur ces paths (voir exemple ci-dessus pour plus de clareté).
slow_requests Object Le tableau des 10 requêtes les plus longues, chaque élément du tableau contient un hash avec l'url complète en clé et le temps de la requête en ms en valeur.

Les contraintes de packaging

Configuration et fichier config.ru

Le middleware doit être fourni avec un fichier rackup config.ru fonctionnel et être compatible avec la "norme" rack/rackup. Voici un exemple de fichier config.ru

        use Rack::LiveTraffic, {} #puts here your storage/discovery options if needed

        app = proc do |env|
          [ 200, {'Content-Type' => 'text/plain'}, ['OK'] ]
        end

        run app
      

Stockage, dépendances et versions

Les seuls stockages externes autorisés sont memcached, redis, mongodb et mysql, ils doivent fonctionner avec les paramètres par défaut et sans login/mdp.

Si vous souhaitez utiliser un système de queue externe seuls faye, rabbitmq et ØMQ sont autorisés

Si vous avez besoin d'un daemon et/ou de workers merci d'interfacer avec foreman dans un procfile. Ces daemons doivent être codés en ruby et toutes leurs dépenses décrites dans un Gemfile. Les gems devront s'installer sans autre dépendances que les librairies de dev des dépendances externes autorisées.

Deux versions de ruby sont autorisées ruby 1.8.7 p249 et 1.9.3 p125, utilisez un .rvmrc pour préciser.

Récapitulatif du livrable

Le livrable est un répertoire ayant au moins la structure suivante :

        . – script/clean    # Script de nettoyage des datas au besoin
        | – script/rack-top # Script de lecture des données qui retourne du JSON
        | – config.ru       # Rackfile pour le middleware (see example)
        | – Gemfile         # Gemfile pour les dépendances ruby
        | – Readme.md       # Description les dépendances externes (mongodb...) et des gotchas 
        | – Procfile        # Procfile pour les éventuels daemons ruby
        | – .rvmrc          # Version de ruby si différente de 1.8.7 p249
        | – ...             # Le reste, middleware Rack, ...
      

L'évaluation des résultats

Comment allons-nous déterminer le gagnant ?

Seules seront prises en compte les réponses qui correspondent à la description du défi et aux contraintes de packaging

Une grille d'évaluation sera mise en place, elle couvrira UNIQUEMENT les points suivants:

  • Qualité intrinsèque du middleware: threadsafe, multiprocess ?
  • Performance globale du middleware
  • Scalabilité du stockage/réseau, est-ce que les performances sont constantes en fonction du trafic, est-ce que le stockage grossit inconsidérément, est-ce que le nettoyage si besoin est bloquant, lourd, lent, fragmente le stockage... ?
  • Qualité de l'algorithme de calcul des visiteurs uniques
  • Qualité des calculs par rapport au trafic réel
  • Appréciation globale du code et de la solution

Le jury sera composé de 5 personnes faisant partie ou pas de Dimelo, les membres du jury et leurs collègues ne peuvent pas participer au concours.

Les résultats de leur évaluation seront envoyés à chacun des candidats mais seule la solution du gagnant sera publiée sur ce site avec son code. Les participants et le gagnant restent propriétaires de leur code et peuvent en disposer à leur convenance.

#dimelocontest

Comment nous contacter ?

Posez vos questions sur twitter avec le #hashtag #dimelocontest sur twitter afin que tout le monde puisse en bénéficier s'ils le souhaitent.

Le permalink pour ce contest est http://contest.dimelo.com/2012/03/06/ruby-easter-egg-contest.html.

Envoyer vos réponses à contest at dimelo.com avant le 11 avril 2012 à midi CEST.