Web Sites de Alta Performance, Parte 2: Visão Geral de HTTP

Este é o segundo post da série Web Sites de Alta Performance. Esta série é baseada no livro de Steve Sourders, High Performance Web Sites. Caso não tenha lido o primeiro, leia aqui.

Antes de apresentar cada coisa que pode ser feita para diminuir o tempo de resposta das suas páginas, vou fazer uma breve introdução sobre o protocolo HTTP, e principalmente as partes do Hypertext Transfer Protocol (HTTP) que podem afetar a performance.

A versão mais usada do protocolo é o HTTP/1.1. Mas ainda hoje alguns browsers e servidores ainda usam o HTTP/1.0.  Este é um protocolo cliente/servidor feito de requisições e respostas (Requests e Responses). O browser envia um Request por uma determinada URL, e o servidor que hospeda esta URL retorna com um Response. Os tipos de Requests são GET, POST, HEAD, PUT, DELETE, OPTIONS e TRACE. Focaremos no tipo GET que é o mais comum.

Um Request do tipo GET possui uma URL seguida de headers. Um Response contém um código de status (Status Code), headers e um corpo (body).  Veja um exemplo abaixo, onde a primeira parte é o Request, e a segunda o Response:

GET /js/algumScript.js
HTTP/1.1
Host: meudominio.com
User-Agent:Mozilla/5.0(...) Gecko/20061206 Firefox/1.5.0.9
------------------------------------------------------------
HTTP/1.1
Content-Type: application/x-javascript
Last-Modified:Wed, 22 Feb 2006 04:15:54 GMT
Content-Length: 355

var f = function(){}....

Compressão

O tamanho da Response pode ser reduzido  usando algum tipo de compressão caso ambos, browser e servidor,  tenham suporte para tal compressão. O browser diz que tem suporte a compressão para o servidor usando o header Accept-Encoding. O servidor, por sua vez, diz ao browser que a Response está com compressão ao usar o header Content-Encoding. Por exemplo, o browser pode enviar a Request com o header:
Accept-Encoding: gzip,deflate
Enquanto que o servidor envia a Response com o seguinte header:
Content-Encoding: gzip

Não entrarei em mais detalhes agora, fica aqui apenas esta visão geral mesmo.

Requests Condicionais

Caso o browser tenha uma cópia de um componente (CSS, Javascript, Imagem, ...) no seu cache, mas não sabe ao certo se esta cópia ainda está válida, um Request Condicional é enviado pelo browser. Caso a cópia do cache ainda seja válida, então o browser usa esta cópia local e não baixa novamente o componente, tornando o tempo de resposta mais rápido para o usuário final.

Normalmente o browser sabe se o componente é válido ou não através da data que o componente foi modificado pela última vez. E ele sabe esta data através do header Last-Modified presente na Response. Veja no exemplo de Response acima que foi usado deste header.

Para realizar um Request condicional, o browser envia o Request com o header If-Modified-Since, cujo valor é a data presente na última response no header Last-Modified.  Caso o componente não tenha sido modificado desde esta data, o servidor envia um Response com status code "304 Not Modified", e não envia body nenhum, resultando num Response mais rápido. No HTTP/1.1 ainda existem os headers ETag e If-None-Match para a realização de Requests condicionais. Mas não falarei em detalhes desses no momento.

Expires

Os Requests condicionais e status code 304 ajudam muito no tempo de resposta dos componentes de uma página, porém eles ainda precisam de um ciclo Request/Response entre o browser e servidor. o header Expires elimina esta necessidade deixando bem claro para o browser o prazo de validade do componente, e assim deixando para o browser a mensagem de que ele pode usar a cópia local que ele tem, até a data presente no Expires, sem fazer nenhum Request.

Keep-Alive

O protocolo HTTP é baseado no protocolo Transmission Control Protocol (TCP). No início, nas primeiras implementações de HTTP, cada Request precisava abrir uma nova conexão Socket. Isso era ineficiente pois muitos Requests HTTP de uma mesma página são feitos para um mesmo servidor. As conexões persistentes (Persistent Connections), tambéem conhecidas como Keep-Alive no HTTP/1.0,  foram criadas, então, para resolver esta ineficiência de abrir e fechar várias conexões Socket para um mesmo servidor. Portanto, browsers e servidores podem usar o header Connection para indicar o suporte ao Keep-Alive. Tanto o Request como o Response podem conter:
Connection: Keep-Alive

No HTTP/1.1, o header Connection: Keep-Alive não é mais necessário, mas muitos browsers e servidores ainda usam.

No HTTP/1.1, o que é apropriado de ser usado é o chamado Pipelining, que permite múltiplos Requests numa mesma conexão Socket, e é mais performático do que Persistent Connections. Porém, Pipelining não é suportado pelo Internet Explorer, pelo menos até a versão 7 do IE. E também não é ativado por padrão no Firefox até a versão 2. Por enquanto, então, Keep-Alive ainda é a forma mais eficiente de usar conexões socket para HTTP. Ao se tratar de HTTPS, isso é aida mais importante, pois estabelecer uma nova conexão HTTPS é ainda mais demorado.

O protocolo HTTP tem ainda muitos outros detalhes que podem ajudar a tornar suas páginas mais rápidas, mas não vou entrar em outros detalhes aqui. 

Este post foi apenas uma visão geral do protocolo HTTP. Não mostrei ainda como aplicar algumas técnicas que fazem uso dos conceitos apresentados aqui. Isso fica para os próximos capítulos desta série. Abcs

0 comentários: