Otimizando Respostas do Apache

Artigo que mostra como utilizar os módulos mod_deflate e mod_expires do apache para otimizar o tempo de resposta em algumas situações.

performance
Introdução

No artigo Cache de Arquivos no Navegador, vimos como configurar o servidor Apache para utilizar o módulo "mod_expires.c". Neste artigo, veremos sobre a utilização do módulo "mod_deflate.c", e sua ação conjunta com o "mod_expires.c".

O Módulo Expires

O módulo Expires (mod_expires.c) serve para o servidor HTTP informar ao navegador que determinado documento pode ser mantido em cache, por um período de validade. Essa validade pode ser em função do tempo de acesso ou da data de última modificação do arquivo. Para detalhes sobre a utilização deste módulo, recomendo a leitura do artigo Cache de Arquivos no Navegador.

No final das contas, o Módulo Expires reduz substancialmente o tráfego de dados entre cliente e servidor, especialmente se os arquivos mantidos em cache são relativamente grandes.

Este módulo normalmente é utilizado apenas para prover cache de arquivos estáticos, como CSS, JavaScript, imagens, etc. Porém, a estratégia pode ser usada em arquivos gerados dinamicamente, como mostrado no artigo Cache de Arquivos no Navegador (parte 2). Infelizmente, nem sempre é viável utilizar esta estratégia de cache para conteúdo dinâmico, justamente em função da alta dinamicidade do conteúdo.

O Módulo Deflate

O módulo Deflate (mod_deflate.c), por sua vez, é responsável por comprimir o conteúdo do documento enviado do servidor HTTP para o cliente, utilizando algum algoritmo suportado pelo navegador cliente. Com isso, se reduz o tráfego de dados entre servidor e cliente. Por outro lado, isso tem um pequeno custo: no lado do servidor, há um custo para compactar o conteúdo e, no lado do cliente, há um custo para descompactar o conteúdo. Levando isso em consideração, devemos usar o módulo deflate em casos em que o tráfego de dados esteja muito alto. Ou quando o tempo envolvido na compactação/envio/descompactação for menor do que o custo do envio do arquivo original (sem compactação).

Este módulo normalmente é aplicado em arquivos com natureza textual (html, css, javascript, css, etc) ou semi-textual (pdf), pois a compactação é mais significativa. Isso inclui os arquivos html gerados dinamicamente por PHP. Por outro lado, ele é evitado em tipos de arquivos que já possuem compactação, como arquivos zip, gz, bz2, jpg, png, etc.

A configuração para utilização deste módulo se baseia basicamente nas seguintes diretivas:

  • SetOutputFilter - Para habilitar a compressão para todos arquivos.
  • AddOutputFilterByType - Para habilitar a compressão para tipos de arquivos específicos.
  • BrowserMatch - Para especificar regras especiais de acordo com o User-Agent ID.
  • DeflateBufferSize - Para configurar o tamanho do buffer para compressão.
  • DeflateCompressionLevel - Para configurar o nível de compressão, que vai de 1 (menos compressão e maior velocidade) a 9 (maior compressão e menor velocidade).
  • DeflateMemLevel - Para configurar o nível de uso de memória para compressão, que vai de 1 (menos) a 9 (mais).
  • DeflateWindowSize - para configurar o tamanho da janela de compressão, que vai de 1 a 15 e, normalmente, quanto maior o número, maior a taxa de compressão.

Além destas diretivas, é importante configurar a diretiva FileETag para "None", para que o módulo funcione em paralelo ao mod_expires.

Exemplo de configuração

<VirtualHost *:80>
    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/html text/css text/javascript text/plain text/xml text/csv application/rss+xml

        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4\.0[678] no-gzip
        BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

        DeflateCompressionLevel 9
        DeflateMemLevel 9
        DeflateWindowSize 15
        DeflateBufferSize 8096

        FileETag None
    </IfModule>
    <IfModule mod_expires.c>
        ExpiresActive On
        ExpiresByType image/x-icon "access plus 1 month"
        ExpiresByType image/png "access plus 1 month"
        ExpiresByType image/jpeg "access plus 1 month"
        ExpiresByType image/gif "access plus 1 month"
        ExpiresByType text/plain "access plus 1 month"
        ExpiresByType text/xml "access plus 1 month"
        ExpiresByType text/csv "access plus 1 month"
        ExpiresByType text/css "access plus 1 month"
        ExpiresByType text/javascript "access plus 1 month"
    </IfModule>
</VirtualHost>

Neste exemplo, habilitamos o módulo deflate para arquivos de alguns tipos específicos. Em seguida, utilizamos um hack para evitar problemas com alguns navegadores (para mais informações, leia a documentação do mod_deflate.c). Em seguida, configuramos algumas diretivas sobre o nível de compressão e desabilitamos o ETag. No bloco seguinte, habilitamos o mod_expires.c para alguns tipos de arquivo, com tempo de validade de 1 mês.

Para habilitarmos o módulo de compressão para todos arquivos, teríamos que substituir a linha com o AddOutputFilterByType pela linha:

SetOutputFilter DEFLATE

Testar

Para checar se tudo funcionou e, opcionalmente, realizar alguns testes específicos, você pode instalar o plugin Firebug para Firefox. Basta acessar uma página (de preferência que contenha referências para arquivos de estilos, scripts e imagens), então abrir o painel do firebug (com a tecla F12), abrindo a aba "Rede" do plugin e fazendo um refresh (atualizar) no navegador. Será mostrado no plugin todas as requisições realizadas e você pode visualizar os cabeçalhos HTTP envolvidos em cada requisição.

No caso do mod_deflate, você pode notar que os documentos compactados vêm com a diretiva HTTP Content-Encoding: gzip no cabeçalho de resposta.

E no caso do mod_expires, você pode notar que após requisitar a página pela segunda vez, caso um arquivo ainda esteja na validade, será obtido um código de retorno HTTP 304 Not Modified, indicando que o servidor informou ao navegador que ele poderia utilizar o cache que ele guardou ao requisitar o documento pela primeira vez.

No Firefox, se você segurar a tecla Shift e clicar no botão atualizar, ele irá requisitar a página forçando com que todo conteúdo seja recarregado, ou seja, dispensa possíveis caches guardados.

Observações Importantes

É necessário reiniciar o servidor Apache sempre que fizer alguma modificação no seu arquivo de configuração principal.

Atenção: sobre o mod_expires, o Apache só vai colocar as diretivas HTTP "Expires" e "Cache-Controll" nos arquivos gerados dinamicamente se o próprio script não as tiver definido explicitamente. Ou seja, se o seu script PHP gera um conteúdo que não deve ser colocado em cache, você deve incluir as linhas:

header('Expires: max-age=0');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');

Outra solução viável é deixar todo conteúdo estático em um diretório específico, então aplicar a regra de expires apenas para ele, configurando o Apache desta forma:

<VirtualHost *:80>
    ...
    <Location /static>
        <IfModule mod_expires.c>
            ExpiresActive On
            ExpiresDefault "access plus 1 month"
        </IfModule>
    </Location>
</VirtualHost>

Neste exemplo, apenas o conteúdo que estiver no diretório "static" será controlado por cache pelo Apache.

Uma outra forma de se fazer isso é habilitando a utilização de arquivos de configurações locais (normalmente chamados .htaccess), através da diretiva AllowOverride, e criando o arquivo de configurações local no diretório desejado, contendo o seguinte conteúdo:

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresDefault "access plus 1 month"
</IfModule>

0 comentários