Cache no Commerce Cloud
Introdução Este é o primeiro artigo de uma série de duas partes sobre estratégias de cache utilizadas em implementações do Salesforce Commerce Cloud. Embora as estratégias de cache abordadas aqui sejam comuns para a maioria das plataformas de experiência do cliente, esta série está focada especificamente nas ofertas do Salesforce Commerce Cloud com o intuito de compartilhar aprendizados, experiências e melhores práticas da comunidade de arquitetos do Salesforce Commerce Cloud.
O espaço digital está evoluindo com crescentes expectativas dos clientes. O objetivo de praticamente todo comerciante é ter um site rápido e confiável como base para fornecer experiências de consumidor de classe mundial. Conforme o tráfego na internet e o volume de dados aumentam, estratégias de cache adequadas são essenciais para alcançar a velocidade esperada pelos clientes e eficiência da plataforma.
Em resumo, o cache traz a entrega de conteúdo o mais próximo possível do consumidor e reduz longos ciclos de execução do sistema e processamento de dados para fornecer ótimas experiências digitais.
Existe uma ideia comum de que o cache no Salesforce Commerce Cloud significa "adicionar <iscache> a alguns templates", mas há muito mais do que isso. Vamos começar com as diferentes camadas de cache para um caso de uso típico de B2C:
O navegador do comprador O CDN O servidor web O servidor de aplicativos A camada de armazenamento (por exemplo, o banco de dados)
Uma boa estratégia de cache busca mover o conteúdo armazenado o mais próximo possível do usuário; quanto mais camadas precisarem ser percorridas, mais lentos serão os tempos de resposta e menor será o potencial de throughput do site.
Exemplo de caso de uso Vamos olhar para um exemplo que ilustra como uma boa estratégia de cache se parece. Frequentemente, os desenvolvedores trabalham em silos ou têm um entendimento limitado de todas as camadas arquiteturais disponíveis (enquanto têm um entendimento muito bom de uma ou duas dessas camadas). Isso leva a soluções que são limitadas em sua escalabilidade. O exemplo a seguir ilustra o poder de usar uma combinação de camadas em vez de tentar resolver o problema em uma única camada.
Requisito: Para cada produto listado em um resultado de pesquisa, mostrar um ícone de coração que é preenchido (ou colorido) para aqueles itens que são salvos na lista de desejos do consumidor.
Uma solução típica Uma abordagem comum para esse tipo de requisito é que o desenvolvedor backend implemente uma solução que renderize HTML representando o estado da lista de desejos de um determinado produto. Isso é funcionalmente correto, mas problemático, pois o resultado é específico para cada usuário e, portanto, a aplicação precisa calcular dinamicamente essas informações para cada "produto tile" (ou seja, a pequena área de produto mostrada nos resultados de pesquisa), percorrendo todas as camadas arquiteturais.
Uma solução melhor Com uma análise mais detalhada do requisito, fica claro que o conteúdo da lista de desejos não muda com frequência e que, por razões de escalabilidade, seria desejável ter "product tiles" armazenados em cache (sem cálculos dinâmicos). Com isso em mente, uma solução melhor exporia o conteúdo da lista de desejos como um atributo de dados HTML em um include dinâmico pré-existente (por exemplo, informações do cliente ou estado de login no cabeçalho) e, em seguida, atualizaria o status do ícone do coração por meio de JavaScript do lado do cliente. No lado do servidor, essa abordagem não tem quase nenhum custo adicional e a operação no cliente também é relativamente barata.
Essa solução faz uso das camadas disponíveis na ordem que melhor alcança um ótimo desempenho para o consumidor final, ao mesmo tempo que suporta muito mais escala em comparação com a solução típica (no lado do servidor).
Cache no Salesforce Commerce Cloud Agora que você viu um exemplo de fundamentos de cache em ação, vamos nos concentrar em alguns dos aspectos específicos do Salesforce Commerce Cloud. As três camadas arquiteturais que suportam o cache são:
Camada do servidor web → Cache da página Camada do servidor de aplicativos → Caches personalizados (CacheMgr) Camada de armazenamento → Atributos personalizados ou objetos personalizados Cada camada é aplicável a diferentes circunstâncias e cada uma vem com considerações de configuração a serem lembradas à medida que você a implementa.
Cache de página O cache de página está entre os conceitos mais críticos da mistura de cache, pois representa a camada
Exemplo de diferentes URLs:
https://www.domain.com/path?param1=1https://www.domain.com/path?param1=2
(mudança em parametros)
https://www.domain.com/path?param1=1¶m2=abc
(parametro adicional)
https://www.domain.com/path?param2=abc¶m1=1
(mudança na order dos parametros)
https://www.domain.de/path?param1=1
(diferença no domínio)
https://www.domain.com/otherpath?param1=1
(diferença no caminho)
As URLs acima criarão entradas diferentes no cache e podem (inadvertidamente) contribuir para quantidades excessivamente altas de entradas no cache e uma taxa de acerto menor no cache, já que todos esses resultados precisam ser calculados primeiro. É por isso que é importante evitar adicionar parâmetros dinâmicos a includes que provavelmente mudarão com frequência (mas não afetam a resposta). Um anti-padrão comumente aplicado é adicionar um parâmetro de posição para tiles de produto em um resultado de pesquisa, o que leva a um armazenamento em cache muito ineficaz dos tiles. Isso ocorre porque cada tile é armazenado em cache várias vezes, dependendo de sua posição no resultado da pesquisa, enquanto exibe sempre o mesmo produto. Isso é frequentemente feito para permitir a navegação nos resultados de pesquisa na página de detalhes do produto, o que é alcançado passando as informações de pesquisa por meio da URL da página de detalhes do produto. O caso de uso pode ser alcançado aplicando uma solução do lado do cliente, o que aumentará significativamente a taxa de transferência das páginas de pesquisa.
Podem haver parâmetros adicionados às suas URLs que não tenham significado para a sua página, como o ID da campanha de uma campanha de newsletter. O Salesforce Commerce Cloud possui um novo recurso para ignorar parâmetros de URL definidos para o cache eficiente da página. Com esse recurso, você pode ignorar certos parâmetros para fins de armazenamento em cache. Para configurar esses parâmetros, selecione Administração > Recursos. A mesma seção permite armazenar em cache respostas 404, o que melhorará a escalabilidade do seu site também.
Armazenamento em cache personalizado O Salesforce Commerce Cloud também oferece uma solução pronta para personalizar o armazenamento em cache. O armazenamento em cache personalizado significa que a chave do cache será alterada pelos pricebooks atualmente ativos e promoções aplicáveis.
Vamos ver o que isso significaria para dois clientes olhando para a mesma página (ou seja, a exata mesma URL). Para um caso em que o cliente A tem o pricebook X registrado e o cliente B tem o pricebook Y registrado, o mesmo produto (sem alteração na URL) será armazenado em cache duas vezes. Todos os clientes com o pricebook X registrado serão subsequentemente servidos com a respectiva entrada em cache, assim como os clientes com o pricebook Y. Como você pode ver, dependendo do número de pricebooks e promoções disponíveis, isso pode levar a muitas entradas no cache (independentemente do preço real do produto ser diferente) e, portanto, deve ser usado apenas onde necessário.
Implementação
As duas APIs de controle de cache possui o mesmo comportamento
- O
dw.system.Response#setExpires(milliseconds)
script API. Veja a documentação em documentatação para mais detalhes. - E
<ISCACHE>
tag.
IMPORTANTE
A Arquitetura de Referência de Frontend (SFRA) fornece decorators que podem ser usados em vez de setExpires. Os decorators aplicarão tempos de cache pré-configurados.
Historicamente, a tag ISML (<ISCACHE>) era a única opção e a API de script foi introduzida posteriormente. Nós recomendamos fortemente que você descontinue o uso da tag ISML e use a API de script em seu lugar. Ambas as abordagens controlam o cache de toda a resposta, não dos modelos individuais, e, portanto, têm o mesmo efeito. No entanto, ISCACHE pode ser confuso, pois pode sugerir que você está apenas fazendo cache de um modelo (o que, novamente, não é o caso). Mesmo que isso seja entendido pelos desenvolvedores, muitas vezes é difícil entender qual modelo define o comportamento de cache de uma resposta, pois eles podem ser aninhados e cada modelo pode ter sua própria tag ISCACHE (nesse caso, o tempo de cache definido mais baixo será aplicado). Além disso, um modelo pode ser usado em diferentes contextos que requerem políticas de cache diferentes, o que tornaria tudo ainda mais complexo. Ao simplesmente usar a API de script e definir o comportamento de cache no controlador, todos esses desafios essencialmente desaparecem.
O código a seguir mostra um exemplo de uso da API de script.
// SFRA controller cached via decorator
server.get('Show', cache.applyDefaultCache, function (req, res, next) {} );
// set cache time directly at the response (does not rely on SFRA)
response.setExpires(new Date().getTime() + durationInMinutes * 60 * 1000);
// apply personalised caching
response.setVaryBy('price_promotion');
// Cache times do not have to be constants - let's get creative!
// apply layered caching times by product availability levels
var availabilityModel = product.getAvailabilityModel();
if (availabilityModel.isOrderable(50)) {
// cache 5 days when >= 50 orderable
response.setExpires(new Date().getTime() + 120 * 60 * 60 * 1000);
} else if (availabilityModel.isOrderable(20)) {
// cache 1 day when >= 20 orderable
response.setExpires(new Date().getTime() + 24 * 60 * 60 * 1000);
} else if (availabilityModel.isOrderable(5)) {
// cache 4 hours when >= 5 orderable
response.setExpires(new Date().getTime() + 4 * 60 * 60 * 1000);
} else {
// cache 30 minutes when < 5 orderable
response.setExpires(new Date().getTime() + 30 * 60 * 1000);
}
Caching a nível de aplicação
Alguns endpoints (páginas inteiras ou includes remotos) precisam fornecer informações dinâmicas (como dados do consumidor ou informações do carrinho) e, portanto, a paginação não pode ser aplicada. Essas páginas podem incorporar os resultados de cálculos caros que podem ser armazenados em cache para reduzir o tempo de processamento geral da solicitação dinâmica. Um exemplo proeminente é a "configuração como código". Isso é típico (mas não exclusivo) de clientes com muitas marcas e países. A configuração é armazenada em arquivos JSON que podem ser estendidos por substituições específicas de marca e país. Embora ler um arquivo JSON e mesclar objetos JavaScript não seja, em si, uma operação cara, dada a frequência dessa operação, ela pode consumir uma quantidade significativa de tempo de processamento. Ao armazenar em cache a configuração para cada combinação de marca/país, essa recalculação em cada solicitação (e cada include remoto) pode ser evitada, resultando em tempos de renderização de página mais rápidos no site.
Existem várias opções diferentes para armazenar em cache informações no nível da aplicação.
Armazenamento em cache de solicitação
Se as informações precisarem ser salvas dentro de uma única solicitação, os dados podem ser armazenados dentro de um módulo, que manterá seu estado no caso de serem necessários novamente. Essa é uma ótima maneira de salvar dados na solicitação com lógica adicional anexada.
O armazenamento em cache de solicitação pode ser útil se você quiser salvar a loja selecionada pelo cliente, mas não deseja que os desenvolvedores interajam diretamente com ela. O módulo pode então salvar o ID da loja internamente e expor apenas métodos para retornar o próprio objeto da loja ou executar ações com a loja enquanto oculta especificidades de implementação (e mantendo-as em um único lugar central).
Se o caso de uso for apenas para armazenar um pequeno pedaço de dados, pode-se usar request.custom para salvar e ler as informações.
Objetos personalizados
Os objetos personalizados são muito versáteis: podem ser importados e exportados, podem ser escritos e lidos e são persistentes e, portanto, consistentes em todos os servidores de aplicativos. Casos de uso típicos aqui incluem cenários em que os dados em cache não devem se perder. Um caso de uso comum é agir como armazenamento intermediário para dados que serão processados posteriormente. A desvantagem dos objetos personalizados é que eles são armazenados no banco de dados e, portanto, todas as camadas arquitetônicas precisam ser percorridas.
Caches personalizados
Os caches personalizados permitem que os desenvolvedores armazenem uma quantidade limitada de informações. Eles não são compartilhados entre servidores de aplicativos, portanto, os dados não são sincronizados. Portanto, são melhores usados para salvar resultados intermediários de operações caras que precisam ser executadas em solicitações dinâmicas ou operações que ocorrem com muita frequência.
Arquivos
Os caches de arquivos são ótimos para otimizações de tempo de compilação, por exemplo, se os modelos precisarem ser gerados (em cenários em que são usadas linguagens de modelos diferentes do ISML). Eles também são úteis onde o código de desenvolvimento pode ser otimizado ou configurações específicas do ambiente precisam ser criadas.
Sessão Se você precisa armazenar pequenas informações em cache para um determinado usuário, a sessão pode ser a melhor opção. É fácil de implementar e os dados podem ser usados para construir grupos dinâmicos de clientes. Existem duas maneiras de armazenar dados na sessão:
session.custom
- Utilize isso quando os dados precisarem ser usados para criar grupos dinâmicos de clientes. Quando os dados são armazenados em session.custom, a plataforma atualizará os grupos dinâmicos de clientes. Isso pode ser caro, portanto, use com cuidado.
- Quando os dados são armazenados em session.custom, a plataforma atualiza os grupos de clientes dinâmicos. Isso pode ser caro, então use com cuidado.
- Limpar depois do logout
session.privacy
Static content caching
Uma forma ligeiramente diferente de caching é o caching de conteúdo estático, que se refere a imagens, folhas de estilo e JavaScript do lado do cliente - qualquer tipo de arquivo que seja baixado e consumido diretamente pelo navegador. Esses arquivos são entregues pelo servidor de origem e são então armazenados em cache dentro do eCDN.
Os arquivos estáticos são gerenciados diretamente no ambiente ou podem ser incluídos no código. Para este último, eles são frequentemente gerados durante o processo de construção. Uma vez que essas fontes estão no servidor, elas são servidas como estão e não podem conter informações calculadas dinamicamente; assim, são estáticas.
Caching de API Rest (OCAPI)
Salesforce Commerce Cloud também oferece a capacidade de gerenciar o caching de OCAPI declarativamente através da configuração de OCAPI. Esse caching é gerenciado pela camada do controlador de aplicação. Você pode configurar as configurações de OCAPI no Business Manager (Administração > Desenvolvimento de Site > Configurações da API de Comércio Aberto). Essas configurações de cache podem ser configuradas em cada nível de API individualmente.
Replicação e limpeza de cache
Todos os caches abordados até agora podem ser limpos ou eliminados. Isso é importante entender por duas razões. Primeiro, você deseja garantir que os dados não sejam armazenados em cache por mais tempo do que o desejado e, segundo, você deseja evitar a limpeza frequente de cache, o que afetará negativamente o desempenho e a escalabilidade.