Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Quando la tua applicazione Django non va abbastanza veloce

Quando la tua applicazione Django non va abbastanza veloce

Django mette molta enfasi nel creare applicazioni velocemente. Questo è grandioso! Sviluppare applicazioni velocemente però non sempre significa sviluppare applicazioni veloci.

In questo talk mostrerò alcuni problemi di performance che ho incontrato (o introdotto) nella mia esperienza di sviluppatore. Vedremo esempi in diversi punti dell’applicazione: dai modelli, passando per le viste fino ai serializzatori. Alcuni di questi si sono rivelati facili da trovare e risolvere, altri subdoli o addirittura imbarazzanti. Tutti fortunatamente risolti.

Riccardo Magliocchetti

May 04, 2019
Tweet

More Decks by Riccardo Magliocchetti

Other Decks in Programming

Transcript

  1. Quando la tua
    Quando la tua
    applicazione Django
    applicazione Django
    non va abbastanza veloce
    non va abbastanza veloce
    Riccardo Magliocchetti
    Riccardo Magliocchetti

    View Slide

  2. whoami
    whoami
    Software developer @ Maieutical Labs
    Consultant
    OSS contributor

    View Slide

  3. Ridiculously fast
    Ridiculously fast
    Django was designed to help developers take applications
    from concept to completion as quickly as possible.
    www.djangoproject.com

    View Slide

  4. La mia esperienza
    La mia esperienza
    Ottimizzazioni di piccoli e medi progetti Django in piccoli
    team

    View Slide

  5. DUE REGOLE PER
    DUE REGOLE PER
    OTTIMIZZARE
    OTTIMIZZARE

    View Slide

  6. 1. Don't do it
    Don't do it

    View Slide

  7. 1. Don't do it.
    2. (for experts only)
    (for experts only)
    Don't do it yet.
    Don't do it yet.

    View Slide

  8. 1. Don't do it.
    2. (for experts only) Don't do it yet.
    Not until you have a perfectly clear and unoptimized
    solution.
    Michael A. Jackson
    Principles of Program Design, 1975

    View Slide

  9. Hai raggiunto
    Hai raggiunto
    il product/market t?
    il product/market t?

    View Slide

  10. Quando pensare alle
    Quando pensare alle
    performance
    performance
    Idealmente prima di andare in produzione
    Code review: Quante query fa questo endpoint?

    View Slide

  11. questa URL è lenta
    questa URL è lenta
    Clienti insoddisfatti
    Clienti insoddisfatti

    View Slide

  12. uso
    uso troppa
    troppa RAM
    RAM
    Risorse sprecate
    Risorse sprecate

    View Slide

  13. COME SI OTTIMIZZA?
    COME SI OTTIMIZZA?

    View Slide

  14. Fare meno lavoro
    Fare meno lavoro
    Il codice sta facendo qualcosa che non serve

    View Slide

  15. Far meglio
    Far meglio
    Migliore algoritmo o struttura dati
    High Performance Python, Ian Ozsvald, Micha Gorelick

    View Slide

  16. MISURA PRIMA DI
    MISURA PRIMA DI
    OTTIMIZZARE
    OTTIMIZZARE

    View Slide

  17. Monitoring
    Monitoring
    SaaS: Datadog, New Relic, Elastic APM, etc...
    Prometheus, talk Pycon9 @davidesetti

    View Slide

  18. TOOL OPEN SOURCE
    TOOL OPEN SOURCE

    View Slide

  19. MISURARE RICHIESTE LENTE
    MISURARE RICHIESTE LENTE

    View Slide

  20. jazzband/django-silk
    jazzband/django-silk
    Pro lazione e introspezione di richieste
    Online, non in produzione

    View Slide

  21. Dashboard richieste
    Dashboard richieste

    View Slide

  22. Query per richiesta
    Query per richiesta

    View Slide

  23. SQL query
    SQL query

    View Slide

  24. piglei/uwsgi-sloth
    piglei/uwsgi-sloth
    Analizza richieste lente dai log
    Of ine, per uWSGI
    Attenzione alla media!

    View Slide

  25. View Slide

  26. MISURARE
    MISURARE
    CONSUMO MEMORIA
    CONSUMO MEMORIA

    View Slide

  27. xrmx/pyuwsgimemhog
    xrmx/pyuwsgimemhog
    Trova viste con possibili memory leak dai log
    Of ine, per uWSGI

    View Slide

  28. Come ottimizzare in pratica
    Come ottimizzare in pratica
    1. Fare un database fatto bene
    2. Fare meno query
    3. Fare query meno costose
    4. Fare meno lavoro inutile

    View Slide

  29. Un database
    Un database
    User

    View Slide

  30. Un database più veloce
    Un database più veloce
    Custom User

    View Slide

  31. L'ereditarietà concreta dei
    L'ereditarietà concreta dei
    modelli Django è una trappola
    modelli Django è una trappola
    Usa quella astratta o esplicitamente una relazione

    View Slide

  32. QUERY
    QUERY

    View Slide

  33. Prendere solo quello che serve
    Prendere solo quello che serve
    values() e values_list()

    View Slide

  34. Salvare solo quello che serve
    Salvare solo quello che serve
    - score.save()
    + score.save(update_fields=['points'])

    View Slide

  35. Le query N + 1 uccidono le
    Le query N + 1 uccidono le
    performance dell'applicazione
    performance dell'applicazione

    View Slide

  36. class Room:
    building = models.ForeignKey(Building)
    class Appointment:
    room = models.ForeignKey(Room)
    doctor = models.ForeignKey(Doctor)
    a = Appointment.objects.get(
    id=appointment_id
    )
    print('In {} with {}'.format(a.room, a.doctor))

    View Slide

  37. Per evitare query N + 1
    Per evitare query N + 1
    select_related(), JOIN in SQL
    prefetch_related(), join in Python

    View Slide

  38. select_related()
    select_related()
    class Room:
    building = models.ForeignKey(Building)
    class Appointment:
    room = models.ForeignKey(Room)
    doctor = models.ForeignKey(Doctor)
    - a = Appointment.objects.get(
    + a = Appointment.objects.select_related(
    + 'doctor', 'room__building'
    ).get(
    id=appointment_id
    )

    View Slide

  39. select_related() è greedy
    select_related() è greedy
    + ).select_related(
    + 'doctor', 'room__building'
    ) ^^^^^^^^^^^^^^^^
    SELECT * in JOIN: doctor, room e building

    View Slide

  40. Attenzione a select_related()
    Attenzione a select_related()
    L'admin se nel list_display c'è un solo campo preso da
    una relazione seleziona tutti i modelli delle relazioni
    Memory leak in django 1.11?

    View Slide

  41. Attenzione alle librerie
    Attenzione alle librerie
    children = ListField(
    child=RecursiveField(),
    - source='children.all'
    + source='get_children'
    )

    View Slide

  42. Attenzione alle librerie
    Attenzione alle librerie
    Do less work in MySerializer
    Use django-mptt get_children method instead of
    going straight to the field model.
    /myapi/ does 40% less queries

    View Slide

  43. Il numero di query è testabile
    Il numero di query è testabile
    django.test.TransactionTestCase.assertNumQue
    ries()
    with self.assertNumQueries(2):
    Person.objects.create(name="Aaron")
    Person.objects.create(name="Daniel")

    View Slide

  44. INDICI
    INDICI

    View Slide

  45. Indici: se ltriamo o ordiniamo
    Indici: se ltriamo o ordiniamo
    - complete = models.BooleanField(default=False)
    + complete = models.BooleanField(
    + default=False,
    + db_index=True
    + )

    View Slide

  46. Ordinare non è gratis
    Ordinare non è gratis
    class MyAdmin:
    readonly_fields = ['creation_ts']
    - ordering = ['creation_ts',]
    Remove unuseful ordering in MyAdmin
    Ordering a timestamp without indexes is sloooooow.
    Now the query takes 30 seconds less!

    View Slide

  47. Gli indici non sono gratis
    Gli indici non sono gratis
    class MyModel:
    elements = models.ManyToManyField(Element)
    Indici nella tabella di join:
    Indici nella tabella di join:
    1. PK
    2. FK verso MyModel
    3. FK verso Element
    4. UNIQUE sulle FK

    View Slide

  48. Gli indici ci servono sempre?
    Gli indici ci servono sempre?
    - elements = models.ManyToManyField(Element)
    + # Be aware we don't have indexes here
    + elements = ArrayField(
    + models.IntegerField(),
    + default=[],
    + blank=True
    + )

    View Slide

  49. Se gli indici non ci servono
    Se gli indici non ci servono
    Use an array field for MyContainer elements
    Instead of using an m2m. We don't need the field
    for the application, we need it for analytics.
    This let us save 2GB from tables and indexes.

    View Slide

  50. SERIALIZZATORI
    SERIALIZZATORI

    View Slide

  51. Usare il serializzatore giusto
    Usare il serializzatore giusto
    class MySerializer(serializers.ModelSerializer):
    - owner = UserSerializer()
    + owner = serializers.IntegerField(
    + read_only=True
    + )

    View Slide

  52. Esplicito meglio di implicito #1
    Esplicito meglio di implicito #1
    class MySerializer(serializers.ModelSerializer):
    class Meta:
    model = MyModel
    fields = '__all__'

    View Slide

  53. Esplicito meglio di implicito #2
    Esplicito meglio di implicito #2
    class MySerializer(serializers.ModelSerializer):
    class Meta:
    model = MyModel
    exclude = ('owner',)

    View Slide

  54. Non usare i ModelSerializer
    Non usare i ModelSerializer
    per serializzare
    per serializzare

    View Slide

  55. Il context ti è amico
    Il context ti è amico
    class MySerializer:
    - title = serializers.CharField(
    - source='assignment.task.title'
    - )
    + title = serializers.SerializerMethodField()
    + def get_title(self, obj):
    + titles = self.context.get('titles')
    + return titles[obj.assignment_id]
    select_related() e prefetch_related()
    sarebbero state dispendiose

    View Slide

  56. Altre cose da guardare
    Altre cose da guardare
    e
    e
    e la documentazione del Database
    django ≥ 2
    defer() only()
    union
    Prefetch
    aggregate() annotate()
    Database functions
    FilteredRelation()
    EXPLAIN

    View Slide

  57. Letture interessanti
    Letture interessanti
    The Dramatic Bene ts of Django Subqueries and
    Annotations
    Django ORM Cookbook
    Updating a Django queryset with annotation and
    subquery

    View Slide

  58. Conclusioni
    Conclusioni
    Misura prima di eventualmente ottimizzare
    Pensa alle performance
    Piccoli cambiamenti possono dare grandi risultati
    Conoscere SQL aiuta

    View Slide

  59. Grazie! Domande?
    Grazie! Domande?
    github.com/xrmx
    speakerdeck.com/xrmx
    @rmistaken

    View Slide