O tamanho dos registros TLS podem ter um impacto significante no tempo de carregamento da página de seu aplicativo. Na verdade, no pior dos casos, que infelizmente é também o mais comum na web hoje, ele pode atrasar o processamento dos dados recebidos por vários ciclos! Em redes móveis, isso pode se traduzir em centenas de milissegundos de uma latência desnecessária.
A boa notícia é que isso é relativamente simples de se corrigir caso o seu servidor TLS tenha suporte para a correção. Entretanto, vamos primeiro dar um passo atrás e entender o problema: o que é um registro TLS, por que precisamos dele e por que o tamanho do registro afeta a latência dos seus aplicativos?
Criptografia, autenticação e integridade de dados
O TLS fornece três serviços essenciais: criptografia, autenticação e integridade de dados. Criptografia ofusca os dados, autenticação fornece um mecanismo para verificar a identidade de quem acessa, e integridade fornece um mecanismo para detectar mensagens falsas e adulteradas.
Cada conexão TLS começa com um handshake, em que quem acessa negocia a cifra criptográfica, estabelece as chaves secretas para a conexão e autentica as identidades (na web, normalmente só autenticamos a identidade do servidor – ex.: esse é realmente o meu banco?). Uma vez que esses passos foram cumpridos, podemos começar a transferir dados do aplicativo entre o cliente e o servidor. É aqui que entram em cena a integridade dos dados e a otimização do tamanho do registro.
Antes dos dados do aplicativo serem criptografados, eles são divididos em pedaços menores de até 16KB, e cada um dos pedaços resultantes é assinado com um código de autenticação de mensagem (Message Authentication Code em inglês, ou MAC). O pedaço resultante é então criptografado e o MAC junto com alguns outros metadados do protocolo formam um “registro TLS”, que é então enviado ao cliente.
Quem recebe reverte a sequência. Primeiro, os bytes são agregados até que um ou mais registros completos estejam no buffer (como mostra o diagrama acima, cada registro especifica seu tamanho e cabeçalho) e só quando o registro está disponível por inteiro é que a carga será descriptografada, o MAC é computado mais uma vez para os dados descriptografados e, finalmente, verificado em relação ao MAC contido no registro. Se os hashes baterem, a integridade dos dados está garantida e o TLS finalmente libera os dados para o aplicativo acima dele.
Bloqueio head-of-line, registro TLS e latência
O TLS roda sobre o TCP, e o TCP promete entregar todos os pacotes em ordem. Como resultado, o TCP sofre de bloqueio de head-of-line (HOL), no qual um pacote perdido pode reter no buffer todos os pacotes recebidos até que ele seja retransmitido de forma bem-sucedida – caso contrário, o pacote seria entregue fora de ordem! Esse é um conhecido preço a se pagar por qualquer protocolo que rode sobre um transporte confiável e ordenado como o TCP.
Entretanto, no caso do TLS, temos uma camada extra de buffer devido às checagens de integridade! Uma vez que o pacote tenha sido entregue pelo TCP para a camada TLS acima dele, precisamos primeiro acumular todo o registro, então verificar a impressão digital do MAC e, apenas quando essa checagem é positiva, podemos liberar os dados para o aplicativo acima dele. Como resultado, se o servidor emitir dados em pedaços de 16KB, então quem recebe deve também ler os dados a cada 16KB.
Eliminando a latência TLS
Quanto maior o tamanho do registro TLS, mais provável será de incorrermos em ciclos adicionais devido à retransmissão TCP ou à “sobrecarga” de uma janela congestionada. Dito isso, a correção é também relativamente simples: enviar registros menores. Na verdade, para eliminar o problema por completo, configure o tamanho de seu registro TLS para caber em um único segmento TCP.
Se a janela de congestionamento do TCP é pequena (ex.: durante slow-start), ou caso estejamos enviando dados interativos que devem ser processados o mais rápido possível (em outras palavras, a maior parte do tráfego HTTP), então tamanhos de registros menores podem ajudar a mitigar a custosa latência da sobreposição de mais uma camada de buffer.
Configurando seu servidor TLS
A má notícia é que muitos servidores TLS não fornecem um jeito simples de configurar o tamanho do registro TLS e, em vez disso, utilizam o tamanho padrão de 16KB. A boa notícia é que, se você estiver utilizando HAProxy para delimitar o TLS, então você estará com sorte e, dessa forma, talvez tenha apenas que mexer no código fonte do seu servidor (considerando que ele é de código aberto):
- HAProxy expõem tune.ssl.maxrecord como uma opção configurável.
- Nginx define 16KB no código fonte do ngx_event_openssl, que você pode alterar e recompilar.
- Para outros servidores, cheque a documentação!
A navegação web está atrelada à latência, e eliminar ciclos extras é essencial para entregar um melhor desempenho. Todos os servidores do Google estão configurados para começar novas conexões com registros TLS que caibam em um único segmento de rede – é primordial entregar dados úteis ao cliente o mais rápido possível. Seu servidor também deve fazer o mesmo!
PS.: Para mais dicas de otimização TLS, veja o capítulo TLS em High Performance Browser Networking.
***
Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/