Não Escale Servidores, Escale Código!

Ervilis Viana de Souza

import me

ervilisviana@gmail.com

@ervilis

*/ervilis

Escalabilidade

Escalabilidade

Elasticidade

Performance

Escalabilidade = Estar Preparado

Elasticidade = Capacidade de adaptar-se à demanda

Performance = Fazer rápido

Estar preparado!

Usuário

Aplicação

😎

0.1s

😃😃

Estar preparado!

Usuário

Aplicação

😒

2 s

😐😐😐😐😐😐😐😐😐

Estar preparado!

Usuário

Aplicação

😱 

4 s

😕 😕 😕 😕

😕 😕 😕 😕

😕 😕 😕 😕

😕 😕 😕 😕

Estar preparado!

Usuário

Aplicação

😵 

Bad Gateway

😡 😡 😡 😡

😡 😡 😡 😡

😡 😡 😡 😡

😡 😡 😡 😡

😡 😡 😡 😡

😡 😡 😡 😡

😡 😡 😡 😡

😡 😡 😡 😡

😡😡

😡😡

😡

😡

Qual é a solução?

Upgrade no servidor?

(Escalabilidade Vertical)

Talvez

Mais servidores?

(Escalabilidade Horizontal)

Escalabilidade Horizontal

Desafios:

  • Sistema de arquivos
  • Escalar recursos separadamente
  • Cache
  • Elasticidade
  • Automatização

Então qual é a solução?

Estar preparado UAI 😃 

Reduzir consumo de recursos 

pois todo recurso é

Limitado

  • Memória
  • Processador
  • IO ( Leitura e escrita no disco )
  • Rede
  • Dinheiro

Como?

"Não execute código repetidamente para obter o mesmo resultado"

Cache

Cache

😎

Usuário

Aplicação

😎

1s

/noticias

(Cache miss)

0.1s

(Cache hit)

😎

O que podemos cachear?

  • Páginas inteiras
  • Blocos de template
  • Funções
  • Objetos
  • Resultado de rotinas

Como:

Redis

Memcached

Como:


def get_news(request):
    cache = StrictRedis()
    cache_key = 'noticias'
    cache_timeout = 60*60

    news = cache.get(cache_key)

    if not news:
        # Pegamos as notícias no banco
        news = Noticia.get_all()

        # Salvamos ela no cache
        cache.set(cache_key, news, timeout=cache_timeout)
    

    return render("noticias.html", {"news": news}
{% load cache %}


{% cache 3600 sidebar request.user.username %}
    .. sidebar for logged in user ..
{% endcache %}

Como:

import functools


@functools.lru_cache(maxsize=1000)
def my_function(argument):
    # Do something

    return response
from django.views.decorators.cache import cache_page


@cache_page(60 * 15)
def my_view(request):

    # Slow operations

    return HttpResponse(...)

Limpando o cache


class Noticia:

    def save(self):
        cache = StrictRedis()

        # Limpando todas notícias
        cache.remove('noticias')

        # Limpando uma notícia que foi editada
        cache.remove('noticia_' + self.id)
    
        # Apagando o cache de todas as notícias da mesma categoria
        cache.remove('noticia_categoria_' + self.categoria.id)
        
        # ...

Populando o cache


class Noticia:

    def save(self):
        cache = MemCachedClient("localhost", 11211)
        cache_key = 'noticia_' + self.id
        cache_timeout = 3600

        # Salva a instância atual no cache
        cache.set(cache_key, self, timeout=cache_timeout)


        # Limpa o cache geral
        # ....
    

Processamento

síncrono x assíncrono

"Não deixe o usuário esperando por uma requisição que consuma serviços externos"

Processamento síncrono

😡

Usuário

Aplicação

30 s

/enviar_pagamento

Gateway

Pagamento

29 s

Processamento assíncrono

😎

Usuário

Aplicação

1 s

/enviar_pagamento

Gateway Pagamento

Fila

Worker

Notificar o usuário

Performance é importante!

Otimização de código

@profile
def my_func():
    a = [1] * (10 ** 6)
    b = [2] * (2 * 10 ** 7)
    del b
    return a

if __name__ == '__main__':
    my_func()
$ python -m memory_profiler example.py

Line #    Mem usage  Increment   Line Contents
==============================================
     3                           @profile
     4      5.97 MB    0.00 MB   def my_func():
     5     13.61 MB    7.64 MB       a = [1] * (10 ** 6)
     6    166.20 MB  152.59 MB       b = [2] * (2 * 10 ** 7)
     7     13.61 MB -152.59 MB       del b
     8     13.61 MB    0.00 MB       return a

Otimização de código

import cProfile
import re
cProfile.run('re.compile("foo|bar")')


    197 function calls (192 primitive calls) in 0.002 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 re.py:212(compile)
     1    0.000    0.000    0.001    0.001 re.py:268(_compile)
     1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
     1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
     4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
   3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)

Obrigado!

Ervilis Viana de Souza

ervilisviana@gmail.com

@ervilis

Não Escale Servidores, Escale código!

By Ervilis Viana de Souza

Não Escale Servidores, Escale código!

  • 904