Proxy reverso do cache Nginx: como manter o servidor de aplicativos ativo durante a janela de 5 segundos quando o cache expira?

1

Eu tenho um servidor nginx sentado na frente do apache executando o django.

A maior parte do meu site é de conteúdo estático: link

Meu servidor de aplicativos pode manipular as partes que precisam ser dinâmicas (POST, carrinho, status do pedido, faq, etc.).

A maioria dos acessos é feita para páginas estáticas, como páginas de produtos, sobre páginas, solicitações de obtenção de ajax.

Ele lida como um champ exibindo páginas diretamente do memcached. Na verdade, pedi ajuda a SF para determinar meu gargalo aqui: Isso prova um gargalo de largura de banda de rede ? e é limitado pelo limite de tráfego de saída dos meus hosts. portanto, é 100% capaz de qualquer coisa que eu precise. Eu estava todo animado por causa das figuras; mas os números não significam porcaria quando são 40 páginas sendo bombardeadas com "Ei, me faça um novo para o cache!" "Ei eu também!"

O único problema é que, durante o tráfego pesado, no segundo em que meu cache expira em uma determinada página, meu servidor de aplicativos é atingido com milhares de solicitações que atrapalham tudo / possivelmente derrubam o servidor. O que estou imaginando é algo mais como ...

R: O servidor de aplicativos envia automaticamente o conteúdo para o memcached em seu próprio ritmo (porque ele pode certamente preencher o cache ... mas não centenas simultaneamente). O servidor front-end funciona com o que ele possui - nunca tenta obter solicitações de proxy. Inferno, pode jogar uma página em branco para tudo que eu me importo; pelo menos o servidor de aplicativos estará ativo, aceitando pedidos e será capaz de preencher essa página quebrada em algum momento no futuro, em vez de uma espiral de morte descendente onde eu não posso nem pegar meu escudo (memcached). O problema é: eu teria que criar um sistema que determinasse cada página que deveria ser armazenada em cache de vários lugares. O Django sabe quais páginas armazenar em cache; Eu suponho que isso será fácil. Mas nginx - > django: Eu não quero que ele faça proxy em tudo (senão eu estaria na mesma situação); então eu teria que codificar mais lógica em um local separado. Meh.

B: O Nginx pode limitar as conexões ao servidor de aplicativos. Mas como diferenciar entre as solicitações que devem ser enfileiradas no servidor de aplicativos em comparação com os tipos em que eu apenas quero fazer uma única conexão? Afinal, o aplicativo decide se uma página deve ficar em cache ou não. Não quero que ele desconecte as conexões se elas estiverem aguardando no meu servidor de aplicativos por conteúdo dinâmico simples, como detalhes do pedido. Eu construo um ciclo de resposta de solicitação entre o cache / aplicativo que comunica que uma página precisa ser construída? e que os pedidos subsequentes devem ser ignorados?

Blá.

Portanto, considerando que 99% do tráfego é atendido pelo nginx, e meu servidor de aplicativos realmente é interessante apenas para os X% que convertem e acessam uma página dinâmica, o que devo fazer para evitar que meu servidor de aplicativos fique completamente inundado? os poucos segundos em que responde:

Ei você! Deixe-me retornar esta página para você. Mais 1000 pessoas querem isso? Ok, farei isso para ... se puder.

Problema / exemplo do mundo real: hoje, temos um grande aumento nos acessos. Normalmente, não recebemos muito tráfego, mas lançamos nosso produto hoje e os clientes da pré-encomenda entraram como loucos. O servidor está lidando com o tráfego a 20% da capacidade agora, mas houve alguns momentos muito complicados em que quase o perdi quando ele tentou gerar uma página insignificante em que todos estavam clicando quando o temporizador de cache por hora expirou.

Eu peguei freneticamente as páginas mais importantes em cache e tentei mantê-las no cache. Isso foi / não / divertido! Eu também manualmente puxei o HTML do apache rodando em: 8080 e joguei eles no memcached.

Se meu processo do apache ficar sem memória e completamente travado, digamos memcached ou demorou o suficiente para que as chaves expirassem, haveria um ponto de ... "retorno difícil" em que muitas outras pessoas ignorariam o cache que meu servidor ficaria ainda mais sobrecarregado do que o normal / assim normalmente não seria recuperável sem apenas bloquear todas as requisições e começar a encher o cache manualmente.

O que é tipicamente feito para fazer isso funcionar?

Desculpe pelo tipo de fluxo de pensamento. Eu não dormi devido a este ..

# grove urls
# ----------
location / {
    set $use_memcached no;
    if ($request_method = GET) {
        set $use_memcached yes;
    }
    if ($host ~ "^cached") {
        set $use_memcached no;
    }
    if ($request_uri ~ '.{240,}') {
        set $use_memcached no;
    }
    if ($args ~ nginx_bypass_cache=true) {
        set $use_memcached no;
    }
    if ($use_memcached = yes) {
        set $memcached_key "nginx.$request_uri";
        memcached_pass localhost:11211;
    }
    default_type text/html;
    client_max_body_size 50m;
    error_page 404 502 = @cache_miss;
}

location @cache_miss {
    proxy_pass http://127.0.0.1:8080;
    proxy_redirect off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

    client_max_body_size       50m;
    client_body_buffer_size    128k;

    proxy_connect_timeout      60; # time to connect to upstream server
    proxy_send_timeout         300; # time to wait for upstream to accept data
    proxy_read_timeout         300; # time to wait for upstream to return data

    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
}
    
por Yuji Tomita 05.10.2012 / 23:37

1 resposta

1

Se você pode postar sua configuração do nginx, posso ajudá-lo a se preparar melhor!

Geralmente, eu uso o fastcgi_cache / proxy_cache do Nginx com o fastcgi_cache_use_stale / proxy_cache_use_stale

Eu disse as duas opções, porque se você pode rodar o aplicativo de backend usando o fastcgi do Nginx ou outro módulo, então é melhor fazer isso.

Se o Apache no 8080 não puder ser removido, use melhor proxy_cache com proxy_cache_use_stale updating line.

Por favor, forneça sua configuração para que possamos tentar melhorá-la.

==

Adicionada uma configuração de amostra baseada em sua (muito crua, provavelmente precisará de ajustes)

#IMPORTANT outside server{..} block
proxy_cache_path /var/run/nginx-cache levels=1:2 keys_zone=GROVE:500m inactive=60m;
proxy_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale updating;

server {

        #other stuff

        set $no_cache 0;

        # POST requests and urls with a query string should always go to PHP
        if ($request_method = POST) {
                set $no_cache 1;
        }   

    # grove urls
    # ----------
    location / {
        default_type text/html;
        client_max_body_size 50m;

        proxy_pass http://127.0.0.1:8080;
        proxy_redirect off;

        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;


        client_body_buffer_size    128k;

        proxy_connect_timeout      60; # time to connect to upstream server
        proxy_send_timeout         300; # time to wait for upstream to accept data
        proxy_read_timeout         300; # time to wait for upstream to return data

        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;


        proxy_cache_bypass $no_cache;
            proxy_no_cache $no_cache;

            proxy_cache GROVE;
            proxy_cache_valid  60m;
}
    
por 06.10.2012 / 00:11