S'abonner au Flux RSS

mardi, mai 28 2013

Tsung 1.5.0

La version 1.5.0 de Tsung est sortie vendredi 24 mai (1), celle-ci corrige quelques bugs, améliore certain points et contient également des nouvelles fonctionnalités. Ci-dessous la liste de tous les tickets clos sur le bugtrack du projet (2), avec quelques bugfix/amélioration qui me semble important.

Dans les corrections de bugs on notera la correction des dynvars mal définies qui empêchait certain test sur des valeurs lues depuis des modules externes.

  • TSUN-208 - in the jabber plugin, substitutions for raw request doesn't work in some cases.
  • TSUN-209 - If tag doesn't work with Tsung 1.4.2
  • TSUN-212 - Incorrect ERTS version being set on build.
  • TSUN-215 - normal ack timeout shouldn't used for global ack
  • TSUN-217 - If statement breaks on empty string
  • TSUN-218 - Race condition in tsung-recorder
  • TSUN-219 - Site fails to load via proxy recorder
  • TSUN-220 - Large configuration files trigger error
  • TSUN-229 - compatibility with erlang R15B
  • TSUN-230 - can't connect with TLS + ejabberd
  • TSUN-232 - Tsung for bosh protocol doesn't send a empty request to keep the user session alive.
  • TSUN-234 - Error encoding json string with escape_uri
  • TSUN-238 - Content-Length parsing broken
  • TSUN-241 - Invalid link Other in the graph.html
  • TSUN-245 - Message when dtd is not found not trivial

Le format du fichier de dump se voit compléter de 2 nouveaux champs, la substitution dans les cookies est désormais supportée. La commande PATCH est maintenant supportée dans le protocole HTTP, et quelques autres, l'intégralité étant listées ci-dessous.

  • TSUN-174 - add an option to set resource in XMPP
  • TSUN-222 - Support unsubscribe operation for Jabber pubsub module
  • TSUN-228 - allow substitutions on cookies
  • TSUN-236 - Add probability support for servers
  • TSUN-242 - add timestamp and request duration in dump=protocol for http
  • TSUN-246 - http PATCH support

Dans les nouvelles fonctionnalités on notera plus particulièrement le support de BOSH pour le plugin Jabber et le nouveau plugin pour tester les serveurs de files de type AMQP. Il est désormais possible définit également un poids pour chaque session plutôt qu'un pourcentage. Un script perl est désormais inclus afin de calculer les percentile sur les temps de requêtes et de transaction.

  • TSUN-214 - Ability to pass attributes for node creation for XMPP pubsub protocol.
  • TSUN-227 - add new dynamic variable to get server hostname and port
  • TSUN-231 - add option to use weights instead of probabilities for sessions
  • TSUN-239 - add BOSH support
  • TSUN-240 - add websocket support
  • TSUN-244 - Percentile computation
  • TSUN-248 - add AMQP support

Egalement non listée un nouveau type pour les dynvars qui permet de définir une valeur directement sans passer par une évaluation de code.

Dans le fonctionnement interne on notera un changement de format pour ts_file_server, cela fera l'objet d'un autre billet qui proposera une méthode pour supporter la lecture de fichier .csv en 1.4.2 et 1.5.0

Je ne peux que vous encourager à passer à cette nouvelle version dès que possible.

jeudi, mai 23 2013

Modules externes dans Tsung

Une fonctionnalité aussi intéressante que puissante de Tsung est de permetre de générer des paramètres ou des urls depuis des modules externes écrits en erlang. La documentation (1) officielle indique que les modules doivent être déployés dans le répertoire ebin de Tsung qui est généralement un répertoire système non accessible en écriture aux utilisateurs non privilégiés. Il existe une méthode alternative pour ceux qui ne possèdent pas les permissions root sur leurs machines, cela consiste à indiquer le chemin des librairies au niveau erlang en déclarant la variable ERL_LIBS qui contiendra le nom du répertoire contenant vos modules. Les fichiers .beam seront copiés dans un répertoire nommé obligatoirement ebin qui sera placé dans le répertoire indiqué dans ERL_LIBS. A noter que l'on peut indiquer plusieurs répertoires en les séparant par des virgules comme souvent pour les PATH.

Exemple :

ERL_LIBS=/home/rodo/modules

Les fichiers .beam seront dans

/home/rodo/modules/ebin/

jeudi, avril 11 2013

Module tsung de coordonnées aléatoires

Après avoir traité le cas des numéros de tuiles aléatoires j'ai écrit un module de génération d'url géographiques aléatoires.

De nombreux services géographiques utilisent la syntaxe lat=X&lon=Y&zoom=Z dans leur interface, c'est ce cas de figure que va permettre de traiter le module wms_randomcoord présenté ici, le module génére automatiquement la partie lat,lon de l'url et ce de façon aléatoire. Son utilisation dans un scénario Tsung se fait au travers de l'appel de la fonction url/1.

<setdynvars sourcetype="erlang" callback="wms_randomcoord:url">
   <var name="lonlat" />
</setdynvars>

<request subst="true">
    <http url="/?%%_lonlat%%&amp;zoom=12" method="GET" version="1.1"/>
 </request>

Pour ajouter de l'aléatoire au niveau du zoom on pourra jouter une session dans le scénario où on le fera varier entre deux bornes finies.

<session name='zoomrandom' probability='90'  type='ts_http'>
  <setdynvars sourcetype="erlang" callback="wms_randomcoord:url">
    <var name="lonlat" />
  </setdynvars>

  <setdynvars sourcetype="random_number" start="1" end="18">
    <var name="zoom" />
  </setdynvars>

  <request subst="true">
    <http url="/?%%_lonlat%%&amp;zoom=%%_zoom%%" method="GET" version="1.1"/>
  </request>
</session>

Des scenarii d'exemples sont disponibles dans le dépôt github tsung-tricks, voir les fichiers lonlat.xml et lonlat2.xml.

jeudi, avril 4 2013

Test de charge sur un serveur de tuile

J'ai eu par le passé à effectuer des tests de charge sur des serveurs de tuiles comme ceux mis en oeuvre sur le projet OpenStreetMap. Afin d'assurer des requêtes aléatoires sur tous les niveaux de zoom j'avais écrit à l'époque un plugin pour Tsung que je n'avais pas encore pris le temps de publier, voilà qui est chose faite.

Le plugin se nomme wmsosm.erl et est publié sur github en licence GPLv3. Il permet de générer la partie finale de l'url en z/x/y afin de pouvoir l'intégrer dans la balise request du scénario Tsung. L'utilisation se fait en appelant la fonction urlzxy du module wmsosm, voir l'exemple ci-dessous. Le détail de la mise en oeuvre d'un plugin Tsung est décrit dans la [documentation du projet| http://tsung.erlang-projects.org/user_manual.html] je ne m'étendrais pas sur le sujet.

<request subst="true">
  <http url='/%%wmsosm:urlzxy%%.png' version='1.1' method='GET'></http>
</request>

Le choix de la tuile dans un niveau de zoom donné est aléatoire. le choix du niveau de zoom est aléatoire mais avec pondération, le choix est fait de telle sorte que les niveaus de zooms élevés sortent plus souvent, techniquement le tirage est fait dans une liste qui contient 2 fois le zoom 2, 3 fois le zoom 3 et ainsi de suite.

Ci-dessous un exemple d'un extrait d'utilisation du plugin

"GET /7/88/93.png HTTP/1.1"
"GET /16/17017/19589.png HTTP/1.1"
"GET /11/1791/1872.png HTTP/1.1"
"GET /17/47098/51507.png HTTP/1.1"
"GET /17/40683/45092.png HTTP/1.1"
"GET /17/47025/51434.png HTTP/1.1"
"GET /17/38091/42500.png HTTP/1.1"
"GET /3/4/4.png HTTP/1.1"
"GET /10/839/874.png HTTP/1.1"
"GET /15/6096/7382.png HTTP/1.1"
"GET /18/114432/123250.png HTTP/1.1"
"GET /18/139028/149316.png HTTP/1.1"
"GET /3/4/4.png HTTP/1.1"
"GET /16/17609/19814.png HTTP/1.1"
"GET /12/39/200.png HTTP/1.1"
"GET /18/129410/138228.png HTTP/1.1"
"GET /18/117680/126498.png HTTP/1.1"
"GET /4/9/9.png HTTP/1.1"
"GET /10/836/865.png HTTP/1.1"
"GET /6/40/42.png HTTP/1.1"

Je travaille sur une version améliorée du plugin afin de tirer des blocs aléatoires de tuiles plutôt que des tuiles uniques, ce qui se rapprochera plus des cas réels d'utilisation. On déterminera de façon aléatoire une première tuile et des requêtes seront générées de façon ordonnées dans un ensemble de tuiles voisines paramétrable.

mercredi, avril 3 2013

Créer un lot de User dans Django

Lors d'un récent test de charge sur une application Django j'ai eu à créer 10K utilisateurs pour tester la charge sur le processus de login. Ce besoin de création d'utilisateur de test étant récurrent j'ai écrit une commande manage (1) afin de créer facilement un grand nombre d'utilisateurs mais également de conserver leur id pour suppression ultérieure. La liste des ids est affichée sur stdout pour faire au plus simple.

Par défaut on crée 10 utilisateurs et on spécifie comme premier argument le nombre total souhaité.

Le code de la classe, simple et efficace :

"""                                                                                                       
Create users in batch                                                                                     
"""
import json
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User

class Command(BaseCommand):
    help = 'Create test accounts'

    def handle(self, *args, **options):
        nb_accounts = 10
        mac = 0
        userids = []

        if len(args) > 0:
            nb_accounts = int(args[0])

        while mac < nb_accounts:
            username = 'tsung-%04d' % (mac)
            email = 'tsung-%04d@example.com' % (mac)
            password = 'password-%04d' % (mac)
            user = User.objects.create(username=username,
                                       email=email)
            user.set_password(password)
            user.save()
            userids.append(user.id)
            mac += 1

        print json.dumps(userids)

vendredi, mars 29 2013

Logger les requêtes SQL d'un site Django en production

Si il est intéressant d'utiliser un ORM pour manipuler des objets dans une base de données relationnelle il présente également inconvénient de cacher les requêtes réellement exécutées sur la base de données. Tous les frameworks de développement n'intègre pas forcément de moyen simple d'avoir accés aux requêtes, Django permet de faire cela à partir d'extension comme django-devserver (1[https://github.com/dcramer/django...) ou d'autres ; extensions qui sont utilisables en développement ou sur des machines de pre-prod, mais malheureusement pas en production. Disons que l'on ne s'intéressera pas ici aux sites qui utilisent runserver sur leur serveur de prod, humm.

Résumons le contexte on a une application Django en production et on a besoin de récupérer l'intégralité des commandes SQL passées lors d'une opération de bench.

On va pouvoir faire cela simplement car Django intégre de base un (logger) nommé django.db qui va nous permettre de le faire. On va logger toutes les requêtes directement dans un fichier en configurant dans les settings un handler sur un fichier et en utilisant le logger djangodb.

En pratique on ajoute une entrée file dans la section handlers

    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        },
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/tmp/django-sql.log',
        },
    },

et une entrée django.db dans la section loggers qui utilise l'entrée file

    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        'django.db': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
            }
    }

On aura toutes nos requêtes sql dans le fichier /tmp/django-sql.log sous la forme

(0.000) SELECT "graph_dashitem"."id", "graph_dashitem"."dash_id", "graph_dashitem"."graph_id", "graph_dashitem"."order" FROM "graph_dashitem" WHERE "graph_dashitem"."dash_id" = 2 ORDER BY "graph_dashitem"."order" ASC; args=(2,)

Le premier champs contient le temps d'exécution et le dernier la liste d'arguments, on obtient un fichier facilement parsable dans lequel on pourra rechercher les requêtes gourmandes en temps par exemple. La prochaine étape sera de passer les requêtes dans EXPLAIN pour les analyser.

Avertissement si votre site a un fort traffic le log de toutes les requêtes va générer beaucoup de consommation d'IO, et d'espace disque, pensez à désactiver les logs quand vous avez finit votre bench.

mercredi, mars 27 2013

Publication de tsung2graphite sur Pypi

tsung2graphite dispose désormais d'un paquet sur le Python Package Index plus communément connu sous le sobriquet de Pypi. Les adeptes des virtualenv et de pip install pourront utiliser cet outil plus aisément.

Page tsung2graphite sur pypi : https://pypi.python.org/pypi/tsung2graphite

lundi, mars 25 2013

Pousser les logs de tsung dans graphite

La partie majeure du travail lors d'un opération de test de montée en charge d'un site web est l'analyse des résultats, afin de simplifier cette partie je travaille actuellement sur un outil d'aggrégation de données qui regroupera les données systèmes et les logs générés lors d'un benchmark de site web opéré avec tsung (1). Le développement de la première version de cet outil est basé sur graphite (2) qui sera utilisé pour la génération des graphiques. N'existant pas à ma connaissance d'outil permettant de pousser dans graphite les données recueillies par tsung lors d'une opération de bench j'ai commencé l'écriture d'un script python pour effectuer cette opération. Suivant le précepte du 'release early, release often' j'ai publié le script sur la plateforme gitorious afin de le rendre disponible de suite, il est publié sous licence GPL v3.

Le script est actuellement en version 0.2.0 avec les fonctions de base, je l'utilise déjà en production.

mercredi, février 6 2013

PyDeb from PyPI to .deb

Dans mon précédent billet j'évoquais les paquets debian que j'avais réalisé pour Django au sein du projet Pyrede. Cette activité de packaging ayant pris de l'ampleur les paquets seront désormais disponibles au sein du Projet Pydeb.

Le projet PyDEB se compose d'un dépôt de paquets et d'un blog sur lequel je publie les nouveaux paquets ainsi que leurs mises à jour.

Les derniers paquets réalisés sont redis, hamlpy, vectorformats, ...

Le projet Pyrede d'analyse de fichier requirements.txt continue son activité avec PyDEB comme ressource bien évidemment.

mardi, janvier 29 2013

Paquets Debian pour Django

Si j'aime les virtualenv quand je code je reste attachés aux paquets pour le déploiement et j'essaye tant que faire se peut de résister aux 'pip install -r requirements.txt' sur mes machines de production. C'est dans ce contexte que j'ai packagé quelques paquets relatifs à Django que je vais essayer de maintenir au sein du projet Pyrede.

http://pyrede.quiedeville.org/debian/

Le fichier repo.key contient la signature utilisée pour signer les paquets.

- page 1 de 10