Slide 1

Slide 1 text

Uma Black Friday sem catástrofes Jéssica Bonson Principal Engineer no Olist TDC Floripa 2020, Trilha Microservices

Slide 2

Slide 2 text

Jéssica Pauli de C Bonson ● +-8 anos de exp em pesquisa/desenvolvimento ● graduação/mestrado em Ciências da Computação ● foco em dev backend, machine learning e big data Jogos RPG Canto Hobbies:

Slide 3

Slide 3 text

Maior loja nos principais marketplaces do Brasil. Arquitetura em microsserviços e serverless. Python. Go. PostgreSQL. AWS. Heroku. 20+ APIs 120+ serviços 3m+ produtos 30k+ logistas 10m+ anúncios 200k+ pedidos em maio/2020

Slide 4

Slide 4 text

Arquitetura do Olist

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Techstack ● Python 3 ● Django Rest Framework (DRF) ● Heroku ● Postgres ● AWS (API Gateway, SQS, SNS, S3, IAM, Lambda, RDS, Athena, ...) ● Outros: Redis, Javascript, Go, Lambda, ElasticSearch, ...

Slide 9

Slide 9 text

Onde melhorar? Como medir? Como melhorar?

Slide 10

Slide 10 text

Onde melhorar?

Slide 11

Slide 11 text

Elastic APM

Slide 12

Slide 12 text

pgHero

Slide 13

Slide 13 text

Como medir?

Slide 14

Slide 14 text

Django-silk https://github.com/jazzband/django-silk Profiling e inspeção

Slide 15

Slide 15 text

Siege https://github.com/JoeDog/siege Teste de carga e benchmark

Slide 16

Slide 16 text

Locust https://locust.io/ Teste de carga com scripting em Python

Slide 17

Slide 17 text

Como melhorar?

Slide 18

Slide 18 text

Acesso ao Banco de Dados

Slide 19

Slide 19 text

Exemplo Para 100 Books, onde cada um tem uma FK para um Publisher... queryset = Book.objects.all() for book in queryset: print(str({'name': book.name, 'publisher': book.publisher.name}))

Slide 20

Slide 20 text

Exemplo Para 100 Books, onde cada um tem uma FK para um Publisher... queryset = Book.objects.all() for book in queryset: print(str({'name': book.name, 'publisher': book.publisher.name})) # 101 queries

Slide 21

Slide 21 text

Exemplo: select_related Para 100 Books, onde cada um tem uma FK para um Publisher... queryset = Book.objects.all() for book in queryset: print(str({'name': book.name, 'publisher': book.publisher.name})) # 101 queries queryset = Book.objects.select_related('publisher').all() for book in queryset: print(str({'name': book.name, 'publisher': book.publisher.name})) # 1 query

Slide 22

Slide 22 text

Exemplo Para 10 Stores, onde cada uma tem 10 Books, em uma relação many-to-many... queryset = Store.objects.all() for store in queryset : books = [book.name for book in store.books.all()] print(str({'name': store.name, 'books': books}))

Slide 23

Slide 23 text

Exemplo Para 10 Stores, onde cada uma tem 10 Books, em uma relação many-to-many... queryset = Store.objects.all() for store in queryset : books = [book.name for book in store.books.all()] print(str({'name': store.name, 'books': books})) # 11 queries

Slide 24

Slide 24 text

Exemplo: prefetch_related Para 10 Stores, onde cada uma tem 10 Books, em uma relação many-to-many... queryset = Store.objects.all() for store in queryset: books = [book.name for book in store.books.all()] print(str({'name': store.name, 'books': books})) # 11 queries queryset = Store.objects.prefetch_related('books') for store in queryset: books = [book.name for book in store.books.all()] print(str({'name': store.name, 'books': books})) # 2 queries

Slide 25

Slide 25 text

Exemplo: prefetch_related com filtro Para 10 Stores, onde cada uma tem 10 Books, em uma relação many-to-many... queryset = Store.objects.prefetch_related('books') for store in queryset: books = [book.name for book in store.books.filter(price__range=(250, 300))] print(str({'name': store.name, 'books': books}))

Slide 26

Slide 26 text

Exemplo: prefetch_related com filtro Para 10 Stores, onde cada uma tem 10 Books, em uma relação many-to-many... queryset = Store.objects.prefetch_related('books') for store in queryset: books = [book.name for book in store.books.filter(price__range=(250, 300))] print(str({'name': store.name, 'books': books})) # 12 queries

Slide 27

Slide 27 text

queryset = Store.objects.prefetch_related( Prefetch('books', queryset=Book.objects.filter(price__range=(250, 300)))) for store in queryset: books = [book.name for book in store.books.all()] print(str({'name': store.name, 'books': books})) # 2 queries Exemplo: prefetch_related com filtro

Slide 28

Slide 28 text

Exemplo

Slide 29

Slide 29 text

Suporte a Partial Response

Slide 30

Slide 30 text

django-rest-framework-jsonmask

Slide 31

Slide 31 text

Exemplo: Endpoint de autenticação

Slide 32

Slide 32 text

Como usar? ● Herdar rest_framework_jsonmask.views.OptimizedQuerySetMixin ● Herdar rest_framework_jsonmask.serializers.FieldsListSerializerMixin

Slide 33

Slide 33 text

Renderização

Slide 34

Slide 34 text

django-rest-framework-rapidjson ou drf-ujson-renderer /seller-orders/ Antes: Time per request: 1030.060 [ms] (mean) Depois: Time per request: 973.138 [ms] (mean) /orders/ Antes: Time per request: 12512.722 [ms] (mean) Depois: Time per request: 1837.474 [ms] (mean)

Slide 35

Slide 35 text

Melhorias de Banco de Dados ● Adicionar/Remover índices no BD ● Reestruturar relações no BD ● Ativar full text search do Postgres ● Réplica de leitura do BD ● Dumps de dados antigos de histórico para NoSQL ● Particionamento

Slide 36

Slide 36 text

Melhorias de Arquitetura ● Usar cache ● Usar código assíncrono ● Evitar ponto único de falha ● Dividir APIs e serviços que ficarem muito grandes ● Evitar contadores em paginação ● Implementar padrão circuit-breaker ● Conteinerização

Slide 37

Slide 37 text

Valeu! @jpbonson @jessica.bonson

Slide 38

Slide 38 text

Referências https://medium.com/better-programming/django-select-related-and-prefetch-related-f23043fd635d https://medium.com/@lucasmagnum/djangotip-select-prefetch-related-e76b683aa457 https://dizballanze.com/django-project-optimization-part-1/ https://k6.io/blog/comparing-best-open-source-load-testing-tools https://docs.djangoproject.com/en/1.8/topics/db/optimization/#understand-querysets https://docs.djangoproject.com/en/1.11/ref/models/querysets/#django.db.models.query.QuerySet.select_related https://medium.com/@hansonkd/performance-problems-in-the-django-orm-1f62b3d04785 http://pythonclub.com.br/django-introducao-queries.html