"Primeiro, faça funcionar - depois faça mais rápido" Nem sempre está certo

Você pode ter ouvido o conselho de programação "Primeiro, faça funcionar - depois acelere".. Não é totalmente errado. No entanto, sem o contexto adequado, tende a ser mal interpretada e não aplicada corretamente.

A dica deve impedir que o desenvolvedor otimize prematuramente o código, que pode nunca ser executado - ou é executado tão raramente, que uma otimização não teria um impacto suficiente para justificar o esforço que está sendo colocado na otimização. Além disso, a otimização pode levar a códigos mais complexos e, portanto, introduzir erros. Portanto, se você for um desenvolvedor, não gaste muito tempo na microotimização de cada linha de código. Certifique-se apenas de escolher as estruturas de dados, os algoritmos e as bibliotecas corretos e aguardar a análise do ponto de acesso de um profiler para ver onde uma otimização mais completa pode aumentar o desempenho geral.

Decisões e artefatos de arquitetura

No entanto, o conselho "Primeiro fazê-lo funcionar - depois fazê-lo rápido" é totalmente errado quando se trata de decisões "arquitetônicas". O que são decisões arquitetônicas? Simplificando, são as decisões que são caras, difíceis e/ou impossíveis de serem alteradas posteriormente. Lembre-se, que "caro" às vezes é o mesmo que "impossível". Por exemplo, quando seu projeto está ficando sem orçamento, alterações caras são impossíveis de serem implementadas. Mudanças na infraestrutura são o primeiro tipo de mudanças nessa categoria que vem à mente da maioria das pessoas. Mas há também outro tipo de artefatos "arquitetônicos" que podem se tornar muito desagradáveis de mudar:

  1. Partes do código no "centro" de um aplicativo, no qual muitas outras partes dependem. Alterar isso requer que todas as dependências sejam alteradas e testadas novamente de uma só vez.

  2. Artefatos, que estão envolvidos em algum cenário assíncrono e dependente de tempo em que a entrada - e, portanto, o comportamento do sistema pode variar muito aleatoriamente. As alterações podem ter efeitos imprevisíveis e ser difíceis de testar.

  3. Padrões de software que são usados e reutilizados repetidamente, em todas as partes do sistema. Se o padrão do software ficar abaixo do ideal, todos os artefatos que usam o padrão precisarão ser recodificados.

Lembra? No topo desta página dissemos, que o Dispatcher é uma parte essencial de um aplicativo AEM. O acesso a um aplicativo web é muito aleatório - os usuários estão chegando e indo em momentos imprevisíveis. No final, todo o conteúdo será (ou deve) ser armazenado em cache no Dispatcher. Portanto, se você prestasse muita atenção, perceberia que o armazenamento em cache poderia ser visto como um artefato "arquitetônico" e, portanto, deveria ser entendido por todos os membros da equipe, tanto desenvolvedores quanto administradores.

Não estamos dizendo que um desenvolvedor deve realmente configurar o Dispatcher. Eles precisam conhecer os conceitos, especialmente os limites, para garantir que seu código também possa ser aproveitado pela Dispatcher.

O Dispatcher não melhora magicamente a velocidade do código. Um desenvolvedor precisa criar seus componentes tendo a Dispatcher em mente. Portanto, ele precisa saber como funciona.

Armazenamento em cache do Dispatcher - Princípios básicos

Dispatcher as Caching Http - Balanceador de carga

O que é a Dispatcher e por que ela é chamada de "Dispatcher"?

O Dispatcher é

  • Em primeiro lugar, um cache

  • Um proxy reverso

  • Um módulo para o servidor Web Apache httpd, adicionando recursos relacionados ao AEM à versatilidade do Apache e trabalhando sem problemas junto com todos os outros módulos do Apache (como SSL ou até mesmo SSI, como veremos mais tarde)

Nos primeiros dias da Web, você esperaria algumas centenas de visitantes de um site. Uma configuração de um Dispatcher, "despachado" ou balanceamento da carga de solicitações para um número de servidores de publicação AEM e que normalmente era suficiente - portanto, o nome "Dispatcher". Atualmente, no entanto, essa configuração não é mais usada com muita frequência.

Mais adiante neste artigo, veremos diferentes maneiras de configurar sistemas Dispatchers e Publish. Primeiro, vamos começar com algumas noções básicas de armazenamento em cache http.

Funcionalidade básica de um Cache do Dispatcher

Funcionalidade básica de um Cache do Dispatcher

Os conceitos básicos do dispatcher são explicados aqui. O dispatcher é um simples proxy reverso de cache com a capacidade de receber e criar solicitações HTTP. Um ciclo normal de solicitação/resposta é semelhante a:

  1. Um usuário solicita uma página
  2. O Dispatcher verifica se já tem uma versão renderizada dessa página. Suponhamos que seja a primeira solicitação para essa página e que o Dispatcher não possa encontrar uma cópia local em cache.
  3. O Dispatcher solicita a página do sistema Publish
  4. No sistema Publish, a página é renderizada por um modelo JSP ou HTL
  5. A página é retornada ao Dispatcher
  6. O Dispatcher armazena a página em cache
  7. O Dispatcher retorna a página ao navegador
  8. Se a mesma página for solicitada uma segunda vez, ela poderá ser disponibilizada diretamente do cache do Dispatcher, sem a necessidade de renderizá-la novamente na instância do Publish. Isso economiza tempo de espera para o usuário e ciclos de CPU na instância do Publish.

Estávamos falando sobre "páginas" na última seção. Mas o mesmo esquema também se aplica a outros recursos, como imagens, arquivos CSS, downloads de PDF e assim por diante.

Como os dados são armazenados em cache

O módulo Dispatcher aproveita os recursos que o servidor Apache de hospedagem oferece. Recursos como páginas de HTML, downloads e imagens são armazenados como arquivos simples no sistema de arquivos Apache. É simples assim.

O nome do arquivo é derivado pela URL do recurso solicitado. Se você solicitar um arquivo /foo/bar.html, ele será armazenado, por exemplo, em /var/cache/docroot/foo/bar.html.

Em princípio, se todos os arquivos forem armazenados em cache e, portanto, armazenados estaticamente no Dispatcher, você poderá obter o plug do sistema do Publish e o Dispatcher servirá como um simples servidor da Web. Mas isso é apenas para ilustrar o princípio. A vida real é mais complicada. Não é possível armazenar tudo em cache, e o cache nunca está completamente "cheio", pois o número de recursos pode ser infinito devido à natureza dinâmica do processo de renderização. O modelo de um sistema de arquivos estático ajuda a gerar uma imagem aproximada dos recursos do dispatcher. E isso ajuda a explicar as limitações do dispatcher.

A estrutura de URL do AEM e o mapeamento do sistema de arquivos

Para entender a Dispatcher mais detalhadamente, revisitemos a estrutura de um URL de amostra simples. Vamos analisar o exemplo abaixo,

http://domain.com/path/to/resource/pagename.selectors.html/path/suffix.ext?parameter=value&otherparameter=value#fragment

  • http denota o protocolo

  • domain.com é o nome do domínio

  • path/to/resource é o caminho no qual o recurso é armazenado no CRX e, subsequentemente, no sistema de arquivos do servidor Apache

A partir daqui, as coisas diferem um pouco entre o sistema de arquivos AEM e o sistema de arquivos Apache.

No AEM,

  • pagename é o rótulo de recursos

  • selectors significa vários seletores usados no Sling para determinar como o recurso é renderizado. Um URL pode ter um número arbitrário de seletores. Eles são separados por um ponto. Uma seção de seletores pode, por exemplo, ser algo como "french.mobile.fantasia". Os seletores devem conter apenas letras, dígitos e traços.

  • html como sendo o último dos "seletores" é chamado de extensão. No AEM/Sling, também determina parcialmente o script de renderização.

  • path/suffix.ext é uma expressão semelhante a um caminho que pode ser um sufixo da URL. Ele pode ser usado em scripts AEM para controlar ainda mais como um recurso é renderizado. Teremos uma seção inteira sobre esta parte mais tarde. Por enquanto, é suficiente saber que você pode usá-lo como um parâmetro adicional. Os sufixos devem ter uma extensão.

  • ?parameter=value&otherparameter=value é a seção de consulta da URL. É usado para transmitir parâmetros arbitrários ao AEM. URLs com parâmetros não podem ser armazenados em cache e, portanto, os parâmetros devem ser limitados a casos em que são absolutamente necessários.

  • #fragment, a parte do fragmento de uma URL não é passada para o AEM; ela é usada somente no navegador; em estruturas JavaScript como "parâmetros de roteamento" ou para pular para uma determinada parte na página.

No Apache (referencie o diagrama abaixo),

  • pagename.selectors.html é usado como o nome de arquivo no sistema de arquivos do cache.

Se a URL tiver um sufixo path/suffix.ext,

  • pagename.selectors.html foi criado como uma pasta

  • path uma pasta na pasta pagename.selectors.html

  • suffix.ext é um arquivo na pasta path. Observação: se o sufixo não tiver uma extensão, o arquivo não será armazenado em cache.

Layout do sistema de arquivos depois de obter URLs da Dispatcher

Layout do sistema de arquivos depois de obter URLs da Dispatcher

Limitações básicas

O mapeamento entre um URL, o recurso e o nome do arquivo é muito simples.

No entanto, você pode ter notado algumas armadilhas,

  1. Os URLs podem ficar muito longos. Adicionar a parte "caminho" de um /docroot no sistema de arquivos local pode facilmente exceder os limites de alguns sistemas de arquivos. Executar o Dispatcher no NTFS no Windows pode ser um desafio. No entanto, você está seguro com o Linux.

  2. Os URLs podem conter caracteres especiais e tremas. Geralmente, isso não é um problema para o dispatcher. Tenha em mente, no entanto, que o URL é interpretado em muitos lugares do seu aplicativo. Na maioria das vezes, observamos comportamentos estranhos de um aplicativo - apenas para descobrir que uma parte do código raramente usado (personalizado) não foi totalmente testada em relação a caracteres especiais. Você deve evitá-los se puder. E se não puder, planeje testes completos.

  3. No CRX, os recursos têm sub-recursos. Por exemplo, uma página terá várias subpáginas. Isso não pode ser correspondido em um sistema de arquivos, pois os sistemas de arquivos têm arquivos ou pastas.

Os URLs sem extensão não são armazenados em cache

Os URLs sempre devem ter uma extensão. Embora seja possível fornecer URLs sem extensões no AEM. Esses URLs não serão armazenados em cache na Dispatcher.

Exemplos

http://domain.com/home.html está armazenável em cache

http://domain.com/home é não armazenável em cache

A mesma regra se aplica quando o URL contém um sufixo. O sufixo precisa ter uma extensão para ser armazenável em cache.

Exemplos

http://domain.com/home.html/path/suffix.html está armazenável em cache

http://domain.com/home.html/path/suffix é não armazenável em cache

Você pode se perguntar, o que acontece se a parte do recurso não tiver uma extensão, mas o sufixo tiver uma? Nesse caso, o URL não tem nenhum sufixo. Veja o próximo exemplo:

Exemplo

http://domain.com/home/path/suffix.ext

O /home/path/suffix é o caminho para o recurso… portanto, não há sufixo na URL.

Conclusão

Sempre adicione extensões ao caminho e ao sufixo. As pessoas cientes de SEO às vezes argumentam que isso está classificando você nos resultados de pesquisa. Mas uma página não armazenada em cache seria muito lenta e classificada ainda mais.

URLs de Sufixo Conflitantes

Considere que você tem dois URLs válidos

http://domain.com/home.html

e

http://domain.com/home.html/suffix.html

Eles são absolutamente válidos no AEM. Você não veria nenhum problema na sua máquina de desenvolvimento local (sem uma Dispatcher). Provavelmente, você também não encontrará nenhum problema no teste de carga ou UAT. O problema que enfrentamos é tão sutil que escorre pela maioria dos testes. Ela afetará você quando estiver no horário de pico e você estiver limitado no tempo para resolvê-lo, provavelmente não terá acesso ao servidor nem recursos para corrigi-lo. Nós estivemos lá…

Então… qual é o problema?

home.html em um sistema de arquivos pode ser um arquivo ou uma pasta. Não ambos ao mesmo tempo que no AEM.

Se você solicitar home.html primeiro, ele será criado como um arquivo.

As solicitações subsequentes para home.html/suffix.html retornam resultados válidos, mas como o arquivo home.html "bloqueia" a posição no sistema de arquivos, home.html não pode ser criado uma segunda vez como uma pasta e, portanto, home.html/suffix.html não é armazenado em cache.

A posição de bloqueio de arquivos no sistema de arquivos, impedindo que sub-recursos sejam armazenados em cache

A posição de bloqueio de arquivos no sistema de arquivos, impedindo que sub-recursos sejam armazenados em cache

Se você fizer isso no sentido inverso, primeiro solicitando home.html/suffix.html e depois suffix.html será armazenado em cache em uma pasta /home.html no início. No entanto, essa pasta é excluída e substituída por um arquivo home.html quando você solicita home.html subsequentemente como um recurso.

Excluindo uma estrutura de caminho quando um pai é buscado como um recurso

Excluindo uma estrutura de caminho quando um pai é buscado como um recurso

Portanto, o resultado do que é armazenado em cache é totalmente aleatório e depende da ordem das solicitações recebidas. O que torna as coisas ainda mais complicadas é o fato de que você geralmente tem mais de um dispatcher. E o desempenho, a taxa de acerto de cache e o comportamento podem variar de um Dispatcher para outro. Se você quiser descobrir por que o seu site não responde, você precisa ter certeza de que está olhando para a Dispatcher correta com a ordem de armazenamento em cache infeliz. Se você estiver consultando o Dispatcher que, por sorte, tinha um padrão de solicitação mais favorável, você se perderá ao tentar encontrar o problema.

Como evitar URLs em conflito

É possível evitar "URLs conflitantes", em que um nome de pasta e um nome de arquivo "competem" pelo mesmo caminho no sistema de arquivos, quando você estiver usando uma extensão diferente para o recurso quando tiver um sufixo.

Exemplo

  • http://domain.com/home.html

  • http://domain.com/home.dir/suffix.html

Ambos são perfeitamente armazenáveis em cache,

Escolher uma extensão dedicada "dir" para um recurso ao solicitar um sufixo ou evitar usar o sufixo completamente. Há casos raros em que são úteis. E é fácil implementar esses casos corretamente. Como veremos no próximo capítulo, quando falamos sobre invalidação e liberação de cache.

Solicitações Não Armazenáveis em Cache

Vamos analisar um resumo rápido do último capítulo, além de mais algumas exceções. O Dispatcher pode armazenar em cache um URL se ele estiver configurado como armazenável em cache e se for uma solicitação GET. Ele não pode ser armazenado em cache sob uma das exceções a seguir.

Solicitações armazenáveis em cache

  • A solicitação está configurada para ser armazenada em cache na configuração do Dispatcher
  • A solicitação é uma solicitação GET simples

Solicitações ou Respostas Não Armazenáveis em Cache

  • Solicitação negada para armazenamento em cache pela configuração (Caminho, Padrão, Tipo MIME)
  • Respostas que retornam um cabeçalho "Dispatcher: sem cache"
  • Resposta que retorna um cabeçalho "Cache-Control: no-cache|private"
  • Resposta que retorna um cabeçalho "Pragma: no-cache"
  • Solicitação com parâmetros de consulta
  • URL sem extensão
  • URL com um sufixo que não tem uma extensão
  • Resposta que retorna um código de status diferente de 200
  • Solicitação POST