L'ORM de Django est particulièrement efficace, il permet au développeur de complètement abstraire la couche de stockage de données au point de pouvoir utiliser le même code avec SQLite, PostgreSQL ou d'autres bases plus exotiques encore. Lorsque les problèmes de performance surviennent faire le chemin inverse depuis la base vers le code devient un véritable chemin de croix. On verra dans cette présentation comment se faciliter la vie avec quelques outils et méthodes.
1. SQL debug avec Django
Rodolphe Quiédeville
PyConFr 2015
18 octobre 2015
2. #mylife
Admin/Sys tendance DevOps depuis 20 ans
Nourri au logiciel libre exclusivement
Python adepte depuis 10 ans
Consultant en performance des SI(G)
Senior Performance Engineer @PeopleDoc à temps partiel
3. 2 mots sur PeopleDoc
Dématérialisation des documents RH
Conservation des documents 50 ans
Dizaine de projets Django internes
7 plateformes
3 clusters PostgreSQL par plateforme
une centaine de bases de données
50 Millions de documents, +100% tous les ans
4. Problématique majeure
Identifier la source des requêtes SQL relevées dans les logs de
production
SELECT "fish_fish"."id", "fish_fish"."title",
"fish_fish"."body", "fish_fish"."body_size",
"fish_fish"."title_size", "fish_fish"."lang_id",
"fish_fish"."lang"
FROM "fish_fish"
ORDER BY "fish_fish"."body" DESC
6. Démarche
Créer un cercle vertueux entre le métier, la R&D et la
production
Intervenir en développement au plus tôt (modification de
schéma, nouvelles fonctionnalités, ...)
7. Démarche
Créer un cercle vertueux entre le métier, la R&D et la
production
Intervenir en développement au plus tôt (modification de
schéma, nouvelles fonctionnalités, ...)
Analyser les métriques de production (instrumentation, ...)
8. Démarche
Créer un cercle vertueux entre le métier, la R&D et la
production
Intervenir en développement au plus tôt (modification de
schéma, nouvelles fonctionnalités, ...)
Analyser les métriques de production (instrumentation, ...)
Suivre le métier (nouveaux clients, import d’historique, ...)
9. Démarche
Créer un cercle vertueux entre le métier, la R&D et la
production
Intervenir en développement au plus tôt (modification de
schéma, nouvelles fonctionnalités, ...)
Analyser les métriques de production (instrumentation, ...)
Suivre le métier (nouveaux clients, import d’historique, ...)
Anticiper la croissance et les nouvelles fonctionnalités
demandées par le métier
10. Démarche
Créer un cercle vertueux entre le métier, la R&D et la
production
Intervenir en développement au plus tôt (modification de
schéma, nouvelles fonctionnalités, ...)
Analyser les métriques de production (instrumentation, ...)
Suivre le métier (nouveaux clients, import d’historique, ...)
Anticiper la croissance et les nouvelles fonctionnalités
demandées par le métier
Proposer des pistes d’amélioration à la R&D basées sur
les mesures de production (nouveaux index, ré-écriture de
requêtes, ...)
11. Mise en oeuvre de la démarche
sensibilisation à l’utilisation de DDT et query-inspector
configuration des différentes briques pour identification des
sources
analyse des logs SQL des instances de test
analyse des logs SQL en intégration
formation des développeurs à EXPLAIN
tirs de performance tous les jours
13. Les outils développés
Une offre logicielle insuffisante (pour qui ne manipule pas grep,
awk, sed, ...)
django-sql-log
pgstat (PygCat)
14. django-sql-log
Tracer dans les logs de la base de données la view source de
la QuerySet.
fournit un middleware configurable
log l’entrée et la sortie dans une vue
publié sur Github @Novafloss
15. django-sql-log
log de PostgreSQL
duration: 0.174 ms statement: BEGIN
duration: 0.502 ms statement: SET TIME ZONE ’UTC’
duration: 0.053 ms statement: COMMIT
duration: 0.228 ms statement: SHOW default_transaction_isolation
duration: 0.043 ms statement: BEGIN
duration: 0.354 ms statement: SELECT ’django_sql_log_demo.views.Index_START’
duration: 1.221 ms statement: SELECT "dummy_article"."id", "dummy_article"."title", "dummy_ar
duration: 0.118 ms statement: SELECT ’django_sql_log_demo.views.Index_STOP’
duration: 0.067 ms statement: ROLLBACK
duration: 0.179 ms statement: BEGIN
duration: 0.513 ms statement: SET TIME ZONE ’UTC’
duration: 0.054 ms statement: COMMIT
duration: 0.231 ms statement: SHOW default_transaction_isolation
16. pgstat
pgstat.py donne une vision de l’activité SQL
script python monolithique (était)
sortie standard parsable
pour PostgreSQL à partir de 9.4
basé sur l’extension pg_stat_statement
analyse les données des tables catalogue
nécessite un accés exclusif à la base
développement en cours
utilisé chez PeopleDoc dans des jobs Jenkins/Gatling
publié sur gitlab.com:rodo/pg_tools.git
17. Rapport Gatling
Le rapport de Gatling comme source d’inspiration
================================================================================
---- Global Information
--------------------------------------------------------
> request count 185 (OK=185 KO=0 )
> min response time 13 (OK=13 KO=- )
> max response time 3468 (OK=3468 KO=- )
> mean response time 348 (OK=348 KO=- )
> std deviation 278 (OK=278 KO=- )
> response time 50th percentile 322 (OK=322 KO=- )
> response time 75th percentile 431 (OK=431 KO=- )
> mean requests/sec 1.84 (OK=1.84 KO=- )
---- Response Time Distribution
------------------------------------------------
> t < 800 ms 184 ( 99%)
> 800 ms < t < 1200 ms 0 ( 0%)
> t > 1200 ms 1 ( 1%)
> failed 0 ( 0%)
================================================================================
18. pgstat
================================================================================
pgstat start, version 1.4.3
pgstat limit : 100
pgstat ratio : 10
================================================================================
queries that returned more than 100 rows
----------------------------------------
1 ignored queries on 4 signatures
calls 10, rows 80090, rpc 8009.00 (rpc means rows per call)
user : peopleask, sign 7887422347665ceddfe912ce7d0ad776
--------------------------------------
SELECT "user_right"."id", "user_right"."password",
"user_right"."is_superuser", "user_right"."username",
"user_right"."first_name", "user_right"."last_name",
"user_right"."email", "user_right"."is_staff",
"user_right"."is_active", "user_right"."date_joined",
"user_right"."language_code", "user_right"."user_type",
"user_right"."tech_id", "user_right"."timezone",
"user_right"."country_id" FROM "user_right" WHERE (NOT
("user_right"."user_type" = ?) AND "user_right"."is_active" = ?)
================================================================================
pgstat status : KO
================================================================================
19. Filtre manquant
Détection des requêtes sans clause WHERE
================================================================================
queries without where clause
----------------------------
calls 2, rows 19458, rpc 9729.00 (rpc means rows per call)
user : rodo, sign 6430b76b90ca0fa534d1cf382e535818
--------------------------------------
SELECT "fish_fish"."id", "fish_fish"."title" FROM
"fish_fish"
================================================================================
calls 1, rows 9729, rpc 9729.00 (rpc means rows per call)
user : rodo, sign 23e2a60edd4fdb127730b8150d352ffd
--------------------------------------
SELECT "fish_fish"."id", "fish_fish"."title",
"fish_fish"."body", "fish_fish"."body_size",
"fish_fish"."title_size", "fish_fish"."lang_id",
"fish_fish"."lang" FROM "fish_fish" ORDER BY
"fish_fish"."body" DESC
================================================================================
20. Indexation
Quelques statistiques de volumétrie (basées sur les
estimations de PostgreSQL)
================================================================================
10 biggest tables
--------------------------------------------------------------------------------
indexes_tem 387973 public
hotel_hotelcompany 110004 public
duck_duck 44000 public
plum_plum 38342 public
hotel_hotel 30000 public
dali_fishon 20600 public
dali_fish_fishon 15223 public
hotel_hotelskin 12090 public
hotel_hoteldoor 12090 public
hotel_hotelcolor 12090 public
================================================================================
21. Statistiques
pour apprécier la lecture de
main stats, ratio=10
------------------------------------------------------------
pgstat rows total : 7591
pgstat rows / qry : 759
pgstat calls total : 79, limit 200 OK
pgstat calls / qry : 7
pgstat time total : 4547
pgstat time / qry : 454, limit 3000 OK
pgstat rows delta : 19
pgstat rows deltap : 0.25%
pgstat calls delta : 9
pgstat calls deltap : 12.86%
pgstat time delta : 524
pgstat time deltap : 13.02%
pgstat status : OK
------------------------------------------------------------
22. Indexation
Colonnes qui méritent attention
------------------------------------------------------------
column may be indexed
---------------------
score 260 for processes_task.action_needed_company
score 120 for processes_task.action_done_employee
score 180 for processes_task.action_needed_employee
score 20 for user_right.user_type
score 30 for ticket_ticketvisibleby.need_action
score 160 for processes_task.action_done_company
score 10 for processes_process.published
================================================================================
pgstat stop
24. Application name
Travail sur la configuration des workers avec supervisor,
utilisation de l’application name de la libpq
environment=PGAPPNAME=mytask
log_line_prefix = ’%t user=%u,db=%d,app=%a ’ dans
postgresql.conf
... 11:59:39 ... user=rodo,host=10.0.42.2,db=tickets,app=psql
LOG: duration: 1.126 ms
statement: select * from article;
... 11:59:41 ... user=rodo,host=10.0.42.2,db=tickets,app=index_queue
LOG: duration: 0.227 ms
statement: select * from article;
25. TL; TR;
l’ORM n’est pas la solution ultime ...
... ni le mal absolu
tous les logs sont intéressants
l’information existe cherchez là
les tests de perfs remontent des erreurs fonctionnelles
le développeur ne doit pas tester
le debug repose sur le feeling
26. Questions ?
On recrute
Rodolphe Quiédeville
rodolphe.quiedeville@people-doc.com
Document publié sous Licence Creative Commons BY-SA 2.0