Même en se basant sur des références en terme de stabilité il peut arriver que certains combos soient fatals à votre production. C'est ce qui m'est arrivé récemment pour un serveur Nominatim installé pourtant sur une Debian Wheezy, osmosis est utilisé pour la mise à jour continue de la base Nominatim et m'a fait des misères que je m'en vais vous conter.
Admin/Sys
Sous-catégories
mardi, mars 11 2014
Debian, PG9.3, Osmosis et Nominatim
Par Rodolphe Quiédeville le mardi, mars 11 2014, 09:07
vendredi, mars 29 2013
Logger les requêtes SQL d'un site Django en production
Par Rodolphe Quiédeville le vendredi, mars 29 2013, 10:48
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, février 6 2013
PyDeb from PyPI to .deb
Par Rodolphe Quiédeville le mercredi, février 6 2013, 13:01
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.
jeudi, décembre 20 2012
De whoosh à Solr avec Django Haystack
Par Rodolphe Quiédeville le jeudi, décembre 20 2012, 12:43
Sur un déploiement Django avec une indexation réalisée avec Haystack je me suis retrouvé face à un problème bloquant.
L'application doit permettre à différents users unix de la machine d'insérer des données au moyen d'une commande de management de Django ; les objets insérés dans la base de données sont indéxés en temps réels avec un RealTimeSearchIndex. Le peu de volume de données avait orienté le choix du backend d'indexation vers whoosh, whoosh travaillant avec des fichiers locaux l'appel de la commande manage par différents users unix a engendré des problèmes de permissions sur les fichiers d'index. Une première solution de contournement a été d'utiliser la commande sudo mais cela n'est pas satisfaisant sur le long terme sans une formation des utilisateurs à sudo, pour contourner ce problème je me suis orienté vers l'utilisation d'un backend Solr. Je vais décrire ici la mise en oeuvre de cette solution sur une Debian Wheezy car cela ne s'est pas fait sans problèmes.
Installation de Solr
Le choix fait a été d'utiliser Solr avec le server d'application Jetty, l'installation sous Debian est toujours aussi simple qu'apt-get dans notre cas de figure ici il est nécessaire d'installer les paquets
- jetty
- solr-jetty
Le serveur d'indexation étant sur une machine séparée de l'instance Django il faut également installer le package python-pysolr sur le serveur qui fait tourner l'application Django elle même.
Il existe un bug dans le paquet solr-jetty, l'installation créé un lien symbolique cassé.
/var/lib/jetty/webapps/solr
doit pointer vers /usr/share/solr/web
et non vers /usr/share/solr/webapp comme le fait l'installation du package
Schema généré non conforme
Une fois le serveur installé il faut configurer Solr en conformité avec les données de l'application Django, pour cela on génère un fichier nommé schema.xml avec la commande :
manage.py build_solr_schema > schema.xml
Une fois ce fichier généré copiez le sur le serveur Solr dans /etc/solr/conf/schema.xml
J'utilise une version 2.0.0 de Haystack et il est nécessaire de modifier quelque peu le fichier généré pour le rendre compatible avec Solr 3.6.0 présent à l'heure d'écriture de ce billet dans Wheezy.
Tout d'abord il faut remplacer la chaine stopwords_en.txt
par lang/stopwords_en.txt
pour spécifier le bon chemin vers le fichier. (ref)
Un autre problème rencontré qui peut ne pas être votre cas,mais autant le signaler au cas où, lors du premier appel de la commande ./manage.py build_solr_schema
le fichier schema.xml généré contenait des définitions de champs erronés :
<field name="" type="" indexed="True" stored="True" multiValued="" /> <field name="" type="" indexed="True" stored="True" multiValued="" />
Un nouvel appel à build_solr_schema a cette fois généré un fichier valide, une fois copié sur le serveur solr l'indexation fonctionne, et on peut désormais mettre à jour l'index avec manage.py rebuild_index
de même que celui-ci se met à jour lors de l'import des objets dans la base.
Suivant votre configuration réseau vous pourrez vouloir changer le port ou l'interface d'écoute, cela s'effectue dans le fichier /etc/default/jetty ; il ne reste plus enfin qu'à redémarrer jetty.
Ce ne fût pas sans peine, mais au final l'indexation fonctionne et désormais tous les utilisateurs peuvent indexer leurs documents sans problèmes de permissions.
vendredi, novembre 30 2012
Penser à xauth
Par Rodolphe Quiédeville le vendredi, novembre 30 2012, 12:38
Devant installer un outil dont je tairais la nom sur un serveur, outil qui ne se configure qu'avec un client X (ça commence mal) j'ai bloqué sur le X forwarding pendant une demi-journée. Après avoir fait un connexion ssh -X vers le dit serveur impossible de récupérer l'affichage sur ma machine. Un ssh -v m'a mis la puce à l'oreille avec comme dernière ligne :
debug1: Remote: No xauth program; cannot forward with spoofing.
Sans xauth effectivement difficile de reporter l'affichage au travers de la session ssh, la solution simpliste au possible consiste à installer le paquet xauth sur Debian.
apt-get install xauth
Espérons que la prochaine fois j'y penserai plus tôt.
mardi, novembre 13 2012
Session PHP redondées dans memcache
Par Rodolphe Quiédeville le mardi, novembre 13 2012, 11:40
Pour partager les sessions PHP entre les serveurs web au sein d'un cluster il est fréquent d'utiliser le stockage des dites sessions dans un backend memcache. Si ce partage permet de servir un même client depuis n'importe quel serveur tout en conservant ses sessions cela introduit néanmoins un SPOF dans l'architecture, on va voir dans ce billet qu'il est possible de gérer le failover avec 2 ou plus serveurs memcache.
PHP gère depuis la version 3.0.0. de la librairie php-memcache le paramètre memcache.redundancy qui bien que non documenté est déjà fonctionnel, le principe est d'associer ce paramètre à memcache.allow_failover et de définir plusieurs serveurs memcache pour le stockage des sessions.
Dans l'exemple suivant on configure php pour utiliser 2 serveurs qui ont pour ip 10.0.42.1 et 10.0.42.2
; On indique à php de gérer les sessions dans memcache session.save_handler = memcache ; le save_path est composé des adresses des 2 serveurs ; séparées par une virgule session.save_path = "udp://10.0.42.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15,udp://10.0.42.2:11211?persistent=1&weight=1&timeout=1&retry_interval=15" ; permet d'avoir les clés indiques sur tous les serveurs memcache.hash_strategy = consistent ; force php à lire/écrire sur un autre serveur en cas de ; défaillance du premier appelé memcache.allow_failover = 1 ; nb de serveurs memcache + 1 memcache.session_redundancy=3
L'explication de session_redundancy qui vaut le nombre de serveurs memcache + 1 est issue de ce document
Dorénavant si l'un des serveurs memcache est coupé les sessions sont sauvegardées, et à son retour il récupérera les sessions utilisées au fil de l'eau. Cette solution est satisfaisante dans le cas des sessions à durée de vie limitée ; pour une durée de 30 minutes il vous faudra ne pas couper les 2 serveurs memcache à moins de 30 minutes d'intervalles afin d'avoir toujours les sessions actives dans l'un des memcache. Pour conserver des sessions ad vitam aeternam il faudra se tourner vers un stockage dans une base de données ou s'assurer de répliquer le serveur memcache renaissant avec les données du serveur actif.