Repérer un bridage opérateur

Les opérateurs Internet nous proposent des connexions fibres jusqu’à 1GB/s pour 15€/mois. Et cela sans engagement. Dès l’installation, on constate souvent que l’annonce est respectée. Alors oui, l’opérateur pourrait annoncer des débits jusqu’à 1TB/s, tant qu’il y a du débit, il ne ment pas techniquement. Mais est-on loin de ce qui est vendu ?

Quand le lièvre devient tortue…

21 mai 2018, j’ai la fibre chez moi depuis à peine deux semaines ainsi qu’un routeur qui envoi du bois. nperf m’annonce 851,69Mb/s en descendant et 201.47Mb/s en montant. Deal honoré. Fin septembre, je refais la mesure et là j’obtiens 500Mb/s en descendant et 170Mb/s en montant. Histoire d’être sûr, les mesures ont bien entendues été effectuées plusieurs fois sur plusieurs jours. De 85% de débit effectif, je suis donc passé avec les mois à 50% seulement. Pour le paysan que je suis, je n’ai aucune garantie minimale de débit, mais quand même ! Est-ce passager, est-ce que les équipements de l’opérateur sont en souffrance ?

Mi-octobre, changement d’opérateur. Je passe de SFR RED à SFR RED avec le même abonnement. Le payeur est différent mais SFR refuse explicitement un transfert de contrat, d’où changement, pose d’un jour de congé et réception de nouvelles box (même modèle) par le technicien. Je précise pour la suite qu’à part l’ONT (convertisseur signal optique en signal Ethernet), rien n’a changé. Même routeur, même câble optique et je n’ai pas été recâblé au niveau du PMZ (l’armoire verte dans la rue).

Le test sur la « nouvelle » connexion me donne 801Mb/s en descendant et 121Mb/s en montant.

Excuse me, what the fuck?
Excuse me, what the fuck?

la tortue deviEnt scribe

Je me suis donc mis à mesurer régulièrement la qualité de ma connexion Internet. Il existe pour cela une version en ligne de commande de speedtest. Accompagné d’un petit script que voici et alimentant un fichier au format CSV, nous allons donc avoir du quantitatif, qu’on pourra visualiser avec par exemple un simple fichier Excel.

#!/bin/sh

# csv header: date;srv_id;ping ms;download Mbit/s;upload Mbit/s
sfr_id=12746
orange_id=5559
stat_file=/docker/speedtest/stats

cd /docker/speedtest
docker build . -t speedtest

test_server() {
        srv_id=$1

        output=$(mktemp)
        date=$(date -u +"%Y-%m-%d %H:%M:%S")
        docker run --rm speedtest speedtest-cli --simple --server $srv_id > "$output"

        [ $? -ne 0 ] && return 0

        ping=$(grep -i ping "$output" | awk '{print $2}')
        download=$(grep -i download "$output" | awk '{print $2}')
        upload=$(grep -i upload "$output" | awk '{print $2}')

        echo "$date;$srv_id;$ping;$download;$upload" >> "$stat_file"
        rm "$output"
}

test_server $sfr_id
test_server $orange_id

Pour que mes systèmes restent propres, j’utilise une bête image docker contenant le binaire speedtest-cli.

FROM alpine:3.8

RUN set -xe; \
        apk add --no-cache speedtest-cli; \
        ln -s /usr/bin/python3 /usr/bin/python

Il ne reste plus qu’à ajouter le script dans crond et c’est parti.

Le fichier CSV ressemble à :

2018-10-15 10:08:23;5559;6.663;695.91;3.90
2018-10-15 10:36:36;5559;6.831;666.60;3.90
2018-10-15 11:36:38;12746;6.947;769.32;160.76
2018-10-15 11:36:52;5559;6.429;642.82;3.90
2018-10-15 12:00:00;12746;56.589;742.26;127.92
2018-10-15 12:00:20;5559;113.275;672.58;2.83
2018-10-15 12:15:00;12746;6.846;801.72;121.96
2018-10-15 12:15:16;5559;7.419;789.92;3.90
2018-10-15 12:30:00;12746;7.026;692.93;165.77
2018-10-15 12:30:14;5559;71.546;607.98;3.90
2018-10-15 12:45:00;12746;6.771;721.19;150.37
2018-10-15 12:45:15;5559;6.374;563.57;3.90
2018-10-15 13:00:02;5559;7.15;618.68;1.02
2018-10-15 13:15:02;5559;6.53;585.39;3.90
2018-10-15 13:30:02;5559;6.552;420.60;3.90
2018-10-15 13:45:02;5559;6.606;662.53;3.91
2018-10-15 14:00:00;12746;6.656;707.32;134.54
2018-10-15 14:00:16;5559;69.199;586.36;3.12

On y trouve respectivement :

  • la date UTC,
  • l’id du serveur avec lequel s’est fait le test de débit
  • le ping moyen en ms
  • le débit descendant en Mb/s
  • le débit montant en Mb/s

Pour ma part, j’ai testé avec le serveur le plus proche, et le serveur de mon opérateur le plus proche.

Note: il faudra peut-être passer un coup de sed pour corriger le séparateur de décimales avant de faire avaler le fichier par Excel.

Exorciser un dashboard Grafana

J’ai un dashboard Grafana planté, qu’est-ce que je fait ? maman, plus rien ne marche, je ne peux même pas revenir en arrière ?!

Concrètement, que s’est-il passé ? Lors de l’édition d’un dashboard, on a édité une requête quelconque puis enregistré le tout. Depuis, l’affichage de ce dashboard précisément fige l’interface web: on ne peut plus rien faire, tout est figé. Accessoirement on ne peut pas non plus revenir en arrière. Bloqué ? say no more.

Architecture de Grafana

Afin de bien comprendre la solution, il est nécessaire de revenir sur l’architecture de Grafana 2 minutes. C’est un site web qui se découpe en deux parties :

  • le frontend ou dit autrement la partie du site web qui s’exécute exclusivement sur le navigateur. Le frontend est responsable de l’affichage des pages web et particulièrement des graphiques, à partir des données brutes envoyées par le backend, et plus généralement de toute l’interface.
  • le backend, qui agit comme un simple proxy entre le navigateur et les différentes sources de données (ElasticSearch, Prometheus…). Son rôle est d’exécuter les requêtes contenu dans les dashboards auprès des sources de données puis de renvoyer le résultat au navigateur pour que ce dernier puisse rendre les différents graphique composant un dashboard

Les dashboards Grafana sont intégralement sérialisés et stockés sous forme JSON. Le point délicat est que la charge d’interpréter ce fichier pour reconstituer le dashboard n’est pas sous la responsabilité du backend mais du frontend. Son rôle est donc bien plus critique que le simple affichage de jolis dessins.

Malheureusement qui dit frontend dit aussi application écrite en JavaScript. Il suffira d’une minuscule coquille dans un des scripts JavaScript ou dans ce qu’il traite (hint: disons le dashboard sérialisé en JSON par exemple) pour que toute la machine se grippe. Certes le try/catch existe en JavaScript mais l’on ne peut pas dire que cela soit la fonctionnalité la plus utilisée, n’est-ce pas ?

Lorsque cela arrive, tout ce qui fait appel à un peu de code Javascript ne fonctionne plus. Vu que les dashboards sont une single web app, une anomalie JavaScript bloque toute interaction sur le dashboard, incluant édition, suppression, etc…

Persistence

Pour conserver les dashboards, Grafana repose sur une base de données dont le modèle est relativement simple. Par défaut il s’agit de SQLite mais Grafana supporte également MySQL (et ses dérivées) afin de le rendre Hautement Disponible.

Deux tables vont s’avérer particulièrement utiles :

Schéma des tables dashboard et dashboard_version
Extrait du modèle de données de Grafana avec DB Browser for SQLite

La table dashboard contient tous les dashboards existant. La définition du dashboard est enregistré dans la colonne data. Son contenu correspond à ce que l’on a lorsque l’on effectue un export via l’interface web.

La table dashboard_version contient la même chose historisé. Pour un dashboard donné, cette table contiendra toutes les modifications qui ont été effectuées dessus, permettant ainsi de revenir en arrière très simplement. En effet il suffira de prendre le data dans dashboard_version d’une version saine et le placer dans la table dashboard. Pouf, problème résolu !

API

Ce plongeon dans les entrailles était intéressant. La modification en live de la base est la méthode que j’avais employé pour réparer ce graphe parce qu’à ce moment là j’étais justement sur la sauvegarde de l’application mais il existe une solution beaucoup moins intrusive. Vu l’existence du frontend js, ce dernier communique avec le côté serveur à travers une API REST pas mal fichu. En récupérant l’id du dashboard malade, j’aurais simplement eu à faire un POST bien placé.