Django, как и какво да (не) оптимизираме


Йордан Джамбазов

Founder / Програмист @ IO Era
Какво може да се оптимизира?
  • качеството на кода
  • използването на памет
  • оползотворяването на CPU
  • ...
  • програмистско време
Което може да се измери
Оптимизация - модификация с цел подобряване ефективността
Цел: получаване на оптимална система
  • Универсална оптимизация няма
  • Напълно оптимална система няма
  • Оптимизациите понякога изискват trade-off

Какво означава Performance?

  • throughput (заявки/секунда)
  • response time (от заявка до отговор)
  • render time
  • стабилност

Scalability?

Да се справяме с повече трафик.
  • Вертикално - по-силен хардуер
  • Хоризонтално - повече хардуер
Може ли Django да скалира?
Само по себе си - не.

High-level Framework

Спонтанната оптимизация води до спонтанни резултати.

Не предполагай

Profile first:

  • Django Debug Toolbar
  • django-silk
  • cProfile (django-cprofile-middleware)

Познавай ORM-a

            
class Author(models.Model):
    name = CharField()

class Book(models.Model):
    title = CharField()
    author = ForeignKey(Author)
            
          

{% for book in books %}
    {{ book.author.name }} // допълнителна заявка
{% endfor %}
          

Book.objects.select_related('author').all()
Author.objects.prefetch_related('book_set').all()
          
Използвай .count()

books = Book.objects.all()
books.count()  # бързо
len(books)  # по-бавно
{{ books|length }}  # още по-бавно
          
Не използвай .count()

{% if books %}
  

Number of books: {{ books|length }}

    {% for book in books %}
  • {{ book.title }}
  • {% endfor %}
{% endif %}
Добавяй индекси:

class Book(models.Model):
    title = CharField(db_index=True)
    author = ForeignKey(Author)
          
Ускоряват четенето: filter(), exclude(), order_by()

Сортирането не е безплатно


class Book:
    ...
    class Meta:
        ordering = ['title']

Book.objects.all()
Book.objects.all().order_by()  # премахва сортирането на QuerySet-a
          
Не добавяй индекси. Забавят писането.

Познавай базата

  • Оптимизирай заявките
  • indexes
  • Репликиране (master/slave, leader/follower, primary/replica)

Caching

Кеширай - колкото се може повече

  • Мемоизирай - (django.utils.lru_cache)
  • Кеширай QuerySet - (django-cacheops, django-cache-machine)
  • Кеширай темплейтите
  • Кеширай целия HTML Response (Varnish, Squid, nginx)

Varnish

Не кеширай

There are only two hard things in Computer Science: cache invalidation and naming things. -- Phil Karlton

Използвай Django-Compressor

  • Minify-ва CSS и JS файловете
  • Предоставя интеграция с CDN
  • Директно се интегрира в темплейтите

{% load compress %}
{% compress css %}

{% endcompress %}
          

Не използвай Django-Compressor


{% load compress %}
{% compress js %}
// Ще мине development
// ... най-вероятно и staging
// ... на production - 500 (при offline compression mode)
var someVariable = {{ some_variable|safe }};
{% endcompress %}
          

Deployment

  • mod_wsgi
  • uwsgi
  • gunicorn

uWSGI developers are fu*!ing cowards

Both David Cramer and Graham Dumpleton asked why --thunder-lock is not the default when multiprocess + multithread is requested.

This is a good question with a simple answer: we are cowards who only care about money.

"DAMN ! worker 5 (pid: 9531) died :( trying respawn ..."
Не вярвай на дефинитивни твърдения
Не решавай проблеми, които нямаш.
Заобичай Django документацията:
  • Performance and Optimization: http://docs.djangoproject.com/en/1.10/topics/performance/
  • Database access optimization: https://docs.djangoproject.com/en/1.10/topics/db/optimization/
  • Caching: https://docs.djangoproject.com/en/1.10/topics/cache/
  • ..
"Premature optimization is the root of all evil"
Donald Knuth

Q&A

=