Uma Black Friday
sem catástrofes
Jéssica Bonson
Principal Engineer no Olist
Python Brasil, 2020
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
Jogar RPG
Canto
Livros
Hobbies:
Slide 3
Slide 3 text
Maior loja nos principais marketplaces do Brasil.
Arquitetura em microsserviços e serverless.
Python. Go. PostgreSQL. AWS. Kubernetes.
20+ APIs
120+ serviços
3m+ produtos
30k+ logistas
10m+ anúncios
230k+ pedidos
por mês
Django-silk
https://github.com/jazzband/django-silk
Profiling e inspeção
Slide 14
Slide 14 text
Siege https://github.com/JoeDog/siege
Teste de carga e benchmark
Slide 15
Slide 15 text
Vegeta https://github.com/tsenart/vegeta
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
Exemplos
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
Atenção!
Slide 34
Slide 34 text
Conserto
Slide 35
Slide 35 text
Conserto
Slide 36
Slide 36 text
Conserto
Slide 37
Slide 37 text
Renderização
Slide 38
Slide 38 text
django-rest-framework-rapidjson
/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 39
Slide 39 text
Melhorias de Banco de Dados
Slide 40
Slide 40 text
● 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
● Migração para AWS
Slide 41
Slide 41 text
● 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
● Migração para AWS
Slide 42
Slide 42 text
● 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
● Migração para AWS
Slide 43
Slide 43 text
● 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
● Migração para AWS
Slide 44
Slide 44 text
● 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
● Migração para AWS
Slide 45
Slide 45 text
● 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
● Migração para AWS
Slide 46
Slide 46 text
● 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
● Migração para AWS
Slide 47
Slide 47 text
Melhorias de Arquitetura
Slide 48
Slide 48 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 49
Slide 49 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 50
Slide 50 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 51
Slide 51 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 52
Slide 52 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 53
Slide 53 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 54
Slide 54 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 55
Slide 55 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 56
Slide 56 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 57
Slide 57 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização
Slide 58
Slide 58 text
● Usar cache e retries
● Usar código assíncrono
● Cuidado com queries em properties de models
● Evitar ponto único de falha
● ElasticSearch
● Dividir APIs e serviços que ficarem muito grandes
● Evitar contadores em paginação
● Payload SNS mínimo
● Implementar padrão circuit-breaker e throttling
● Conteinerização