it-swarm-pt.tech

O que é cache?

Eu estou constantemente ouvindo sobre a pessoa y teve problema de desempenho x que eles resolveram através do cache.

Ou, como fazer x, y, z em seu código de programas pode prejudicar sua capacidade de armazenamento em cache.

Mesmo em um dos podcasts mais recentes, Jeff Atwood fala sobre como eles armazenam em cache determinados valores para recuperação rápida.

Parece haver alguma ambiguidade nos termos "cache" e "caching" e isso me levou a ficar confuso sobre seu significado em diferentes casos. Se você está se referindo ao cache de aplicativos ou banco de dados, cpu, etc e o que isso significa.

O que é cache e quais são os diferentes tipos?

Do contexto, posso ter uma noção disso, armazenar um valor frequentemente recuperado na memória principal e ter acesso rápido a ele. No entanto, o que é realmente ?

Este Word parece ser usado em muitos contextos diferentes, com um significado ligeiramente diferente (cpu, banco de dados, aplicativo, etc) e eu estou realmente olhando para esclarecer isso.

Existe uma distinção entre o funcionamento do cache em seus aplicativos e o cache do seu banco de dados?

Quando alguém diz que encontrou uma parte do código que prejudicaria o cache e, depois de consertá-lo, melhorou a velocidade do aplicativo, sobre o que eles estão falando?

O cache do programa é algo que é feito automaticamente? Como você permite que valores sejam armazenados em cache em seus programas? Muitas vezes eu li usuários neste site dizer que eles colocaram em cache um valor em sua aplicação, eu sento aqui e me pergunto o que eles significam.

Além disso, o que isso realmente significa quando alguém fala sobre cache de banco de dados? Isso é simplesmente um recurso que eles ativam em seu banco de dados? Você precisa fazer o cache de valores explicitamente ou o banco de dados escolhe quais armazenar em cache para você?

Como começo a armazenar itens em cache para melhorar o desempenho?

Você pode me dar alguns exemplos de como eu posso começar a armazenar valores em cache no meu aplicativos? Ou, novamente, isso é algo que já está feito, sob o capô e eu simplesmente tenho que escrever meu código de uma forma específica para permitir o "cache"?

E quanto ao cache de banco de dados, como eu começo isso? Eu ouvi sobre coisas como memcache. Esse tipo de utilitário é necessário para armazenar em cache em bancos de dados?

Eu estou olhando para obter uma boa distinção entre o cache em aplicativos vs bancos de dados, como eles são usados ​​e como ele é implementado em ambos os casos.

64
KingNestor

O armazenamento em cache é apenas a prática de armazenar dados e recuperar dados de um armazenamento de alto desempenho (geralmente memória) de forma explícita ou implícita.

Deixe-me explicar. A memória é mais rápida de acessar do que um arquivo, uma URL remota (geralmente), um banco de dados ou qualquer outro armazenamento externo de informações que você gosta. Portanto, se o ato de usar um desses recursos externos for significativo , você poderá se beneficiar do armazenamento em cache para aumentar o desempenho.

Knuth disse uma vez que a otimização prematura é a raiz de todo o mal. Bem, o cache prematuro é a raiz de todas as dores de cabeça, tanto quanto eu estou preocupado. Não resolva um problema até que você tenha a problema. Cada decisão que você toma tem um custo que você vai pagar para implementá-la agora e pagar novamente para alterá-la mais tarde, então quanto mais tempo você puder adiar a execução de uma deicsion e mudar seu sistema, melhor.

Então, primeiro identifique que você realmente tem um problema e onde está . Criação de perfil, criação de log e outras formas de teste de desempenho o ajudarão aqui. Eu não posso enfatizar o quão importante é esse passo. O número de vezes que eu vi pessoas "otimizar" algo que não é um problema é impressionante.

Ok, então você tem um problema de desempenho. Digamos que suas páginas estejam executando uma consulta demorada. Se for uma leitura, você tem várias opções:

  • Execute a consulta como um processo separado e coloque o resultado em um cache. Todas as páginas simplesmente acessam o cache. Você pode atualizar a versão em cache sempre que for apropriado (uma vez por dia, uma vez por semana, uma a cada 5 segundos, o que for apropriado);
  • Cache de forma transparente através do seu provedor de persistência, ORM ou qualquer outra coisa. Claro que isso depende de qual tecnologia você está usando. O Hibernate e o Ibatis, por exemplo, suportam o cache de resultados de consulta;
  • Faça com que suas páginas executem a consulta se o resultado não estiver no cache (ou se for "obsoleto", significando que é calculado há mais tempo do que a "idade" especificada) e colocado no cache. Isso tem problemas de simultaneidade se dois (ou mais) processos separados decidirem que precisam atualizar o resultado para que você execute a mesma consulta (cara) oito vezes de uma só vez. Você pode lidar com isso bloqueando o cache, mas isso cria outro problema de desempenho. Você também pode voltar aos métodos de simultaneidade em sua linguagem (por exemplo, APIs de simultaneidade do Java 5).

Se é uma atualização (ou atualizações que precisam ser refletidas em seu cache de leitura), então é um pouco mais complicado, porque não é bom ter um valor antigo no cache e um valor mais novo no banco de dados, de modo que você forneça suas páginas. com uma visão inconsistente dos dados. Mas, falando de maneira ampla, existem quatro abordagens para isso:

  • Atualize o cache e, em seguida, enfileire uma solicitação para atualizar o armazenamento relevante;
  • Escrever por meio de armazenamento em cache: o provedor de cache pode fornecer um mecanismo para persistir a atualização e bloquear o chamador até que essa alteração seja feita; e
  • Cache de write-behind: o mesmo que o cache de write-through, mas não bloqueia o chamador. A atualização acontece de forma assíncrona e separada; e
  • Modelos de persistência como serviço: isso pressupõe que o mecanismo de armazenamento em cache suporta algum tipo de observabilidade (ou seja, ouvintes de eventos de cache). Basicamente, um processo totalmente separado - desconhecido para o chamador - ouve as atualizações de cache e as persiste conforme necessário.

Qual das metodologias acima você escolherá dependerá muito dos seus requisitos, quais tecnologias você está usando e um Host inteiro de outros fatores (por exemplo, é necessário suporte a clustering e failover?).

É difícil ser mais específico do que isso e lhe dar orientação sobre o que fazer sem saber muito mais detalhes sobre o seu problema (como se você tem ou não um problema).

50
cletus

Você provavelmente lerá sobre o armazenamento em cache no contexto de aplicativos da Web. Devido à natureza da Web, o armazenamento em cache pode causar uma grande diferença de desempenho.

Considere o seguinte:

Uma solicitação de página da web chega ao servidor da web, que passa a solicitação para o servidor de aplicativos, que executa algum código que renderiza a página, que precisa ativar o banco de dados para recuperar dinamicamente os dados.

Esse modelo não é bem dimensionado, porque à medida que o número de solicitações para a página aumenta, o servidor precisa fazer a mesma coisa repetidamente, para cada solicitação.

Isso se torna ainda mais um problema se o servidor da Web, o servidor de aplicativos e o banco de dados estiverem em um hardware diferente e se comunicarem pela rede entre si.

Se você tem um grande número de usuários acessando esta página, faz sentido não ir até o banco de dados para cada solicitação. Em vez disso, você recorre ao armazenamento em cache em diferentes níveis.

Cache do Resultset

O armazenamento em cache do Resultset é armazenar os resultados de uma consulta ao banco de dados juntamente com a consulta no aplicativo. Toda vez que uma página da Web gera uma consulta, os aplicativos verificam se os resultados já estão armazenados em cache e, se forem, os extraem de um conjunto de dados na memória. O aplicativo ainda tem que renderizar a página.

Cache de componentes

Uma página da web é composta de diferentes componentes - pagelets, ou o que você quiser chamá-los. Uma estratégia de cache de componente deve saber quais parâmetros foram usados ​​para solicitar o componente. Por exemplo, uma pequena barra de "Notícias mais recentes" no site usa a localização geográfica ou a preferência do usuário para exibir notícias locais. Conseqüentemente, se as notícias de um local forem armazenadas em cache, o componente não precisará ser renderizado e poderá ser retirado de um cache.

cache de página

Uma estratégia para armazenar em cache páginas inteiras é armazenar a string de consulta e/ou os parâmetros de cabeçalho junto com o HTML completamente renderizado. O sistema de arquivos é rápido o suficiente para isso - ainda é muito mais barato para um servidor da Web ler um arquivo do que fazer uma chamada para o servidor de aplicativos para que a página seja renderizada. Nesse caso, todos os usuários que enviarem a mesma string de consulta receberão o mesmo conteúdo em cache.

Combinar essas estratégias de cache de maneira inteligente é a única maneira de criar aplicativos da Web realmente escalonáveis ​​para um grande número de usuários simultâneos. Como você pode ver facilmente, o risco potencial aqui é que, se uma parte do conteúdo no cache não puder ser identificada exclusivamente por sua chave, as pessoas começarão a ver o conteúdo errado. Isso pode ficar bastante complicado, especialmente quando os usuários têm sessões e há contexto de segurança.

14
cdonner

Existem dois significados que eu conheço.


Uma é cache de aplicativo . É quando, se os dados demoram a chegar de algum lugar (por exemplo, através da rede) ou lentos para calcular, então o aplicativo armazena em cache uma cópia dos dados (para que não precise obtê-lo novamente ou recalcular: é já em cache). A implementação de um cache requer um pouco de software de aplicativo extra (lógica para usar o cache) e memória extra (na qual os dados em cache são armazenados).

Isso é "cache" sendo usado como você está citando aqui:

Do contexto, posso ter uma noção disso, armazenar um valor frequentemente recuperado na memória principal e ter acesso rápido a ele.


Outro é cache de CPU , que é descrito em este artigo da Wikipedia . O cache da CPU acontece automaticamente. Se você lê muito a partir de uma pequena quantidade de memória, a CPU pode fazer a maioria dessas leituras a partir do cache. OTOH se você lê uma grande quantidade de memória, ela não pode caber no cache e a CPU deve gastar mais tempo trabalhando com a memória mais lenta.

Isso é "cache" sendo usado como você está citando aqui:

Quando alguém diz que encontrou uma parte do código que prejudicaria o cache e, depois de consertá-lo, melhorou a velocidade do aplicativo, sobre o que eles estão falando?

Isso significa que eles encontraram uma maneira de reorganizar seu código para causar menos Erro no cache .


Quanto a cache de banco de dados , não sei.

5
ChrisW

Há alguns problemas.

Um deles é a granularidade. Seu aplicativo pode ter níveis muito bons de cache além do que o banco de dados faz. Por exemplo, o banco de dados provavelmente armazenará em cache páginas de dados, não necessariamente linhas específicas.

Outra coisa é que o aplicativo pode armazenar dados em seu formato "nativo", enquanto o DB obviamente armazena em cache apenas em seu formato interno.

Exemplo simples.

Digamos que você tenha um usuário no banco de dados, que é feito das colunas: USERID, FIRSTNAME, LASTNAME. Muito simples.

Você deseja carregar um usuário, USERID=123, em seu aplicativo. Quais são os passos envolvidos?

  1. Emitindo a chamada do banco de dados
  2. Analisando a solicitação (SELECT * FROM USER WHERE USERID = ?)
  3. Planejando a solicitação (por exemplo, como o sistema buscará os dados)
  4. Buscando os dados do disco
  5. Transmitindo os dados do banco de dados para o aplicativo
  6. Converter os dados do banco de dados em dados do aplicativo (isto é, USERID em um inteiro, digamos, os nomes em Strings.

O cache do banco de dados, provavelmente, armazena em cache as etapas 2 e 3 (que é um cache de instruções, portanto, não analisará ou replanará a consulta) e armazenará em cache os blocos de disco reais.

Então, aqui está a chave. Seu usuário, USER ID 123, name JESSE JAMES. Você pode ver que isso não é um monte de dados. Mas o banco de dados está armazenando blocos de disco em cache. Você tem o bloco de índice (com o 123 nele), então o bloco de dados (com os dados reais, e todas as outras linhas que se encaixam naquele bloco). Então, o que é nominalmente, digamos, 60-70 bytes de dados realmente tem um impacto de cache e dados no DB de, provavelmente, 4K-16K (depende do tamanho do bloco).

O lado bom? Se você precisar de outra linha que esteja próxima (digamos USER ID = 124), as chances são altas de o índice e os dados já estarem em cache.

Mas mesmo com esse cache, você ainda tem que pagar o custo para mover os dados pela rede (e é sempre através do fio a menos que você esteja usando um banco de dados local, então isso é loopback), e você está "desassociando" os dados . Ou seja, convertendo-o de bits do banco de dados para bits de idioma, para bits de aplicativo.

Agora, uma vez que o Aplicativo obtenha seu USER ID 123, ele coloca o valor em um mapa hash de longa duração.

Se o aplicativo quiser novamente, ele procurará no mapa local, no cache do aplicativo, e salvará os custos de pesquisa, transporte por cabo e empacotamento.

O lado escuro do cache de aplicativos é a sincronização. Se alguém entrar e fizer um UPDATE USER SET LASTNAME="SMITH" WHERE USERID=123, seu aplicativo não "saberá" e, portanto, o cache estará sujo.

Então, há vários detalhes ao lidar com esse relacionamento para manter o aplicativo em sincronia com o banco de dados.

Ter um monte de cache de banco de dados é muito bom para grandes consultas sobre um conjunto "quente" de dados. Quanto mais memória você tiver, mais dados "quentes" você pode ter. Até o ponto, se você puder armazenar em cache todo o BD na RAM, você elimina o atraso de I/O (pelo menos para leituras) de movimentação de dados do disco para um buffer RAM. Mas você ainda tem os custos de transporte e empacotamento.

O aplicativo pode ser muito mais seletivo, como o armazenamento em cache de subconjuntos de dados mais limitados (os bancos de dados apenas bloqueiam o cache), e ter os dados "mais próximos" do aplicativo gera um desempenho muito melhor.

O lado negativo é que nem tudo é armazenado em cache no aplicativo. O banco de dados tende a armazenar dados de maneira mais eficiente, em geral, do que o aplicativo. Você também não tem uma linguagem de "consulta" nos dados armazenados em cache do aplicativo. A maioria das pessoas simplesmente armazena em cache através de uma simples chave e vai a partir daí. Fácil de encontrar USER ID 123, mais difícil para "ALL USERS NAMED JESSE".

O cache do banco de dados tende a ser "livre", você define um número de buffer e o DBMS cuida do resto. Baixo impacto, reduz o I/O geral e os atrasos de disco.

O cache de aplicativos é, bem, específico da aplicação.

Funciona muito bem com dados "estáticos" isolados. Isso é muito fácil. Carregue um monte de coisas para procurar tabelas na inicialização e reinicie o aplicativo se elas forem alteradas. Isso é fácil de fazer.

Depois disso, a complexidade começa a aumentar à medida que você adiciona a lógica "suja", etc.

O que acontece é que, desde que você tenha uma API de dados, você pode armazenar em cache de forma incremental.

Portanto, contanto que você chame getUser(123) em todos os lugares, em vez de acessar o banco de dados, poderá voltar posteriormente e adicionar o armazenamento em cache a getUser sem afetar seu código.

Então, eu sempre sugiro algum tipo de Data Access Layer no código de todos, para fornecer aquele pouco de abstração e camada de interceptação.

4
Will Hartung

o armazenamento em cache está obtendo o resultado de um algoritmo longo ou intensivo de CPU e salvando a resposta para que você não precise executar o algoritmo novamente, basta reutilizar o resultado.

2
Gregor Brandt

O conceito de cache é um termo sobrecarregado aqui. Eu não estou familiarizado com as porcas e parafusos do cache de banco de dados.

Em aplicativos, há dois usos do termo.

Quando alguém diz que encontrou um código Que prejudicaria o armazenamento em cache E depois de consertá-lo, melhorou A velocidade do aplicativo, o que são falando sobre?

Neste caso, eles estão fazendo referência ao cache da CPU. 

O cache da CPU é uma memória na CPU muito mais rápida que a RAM, mas não tem acesso aleatório. O que a CPU decide carregar no cache pode ficar um pouco complicado. Veja Ulrich Dreppers O que todo programador deve saber sobre memória para muitos detalhes.

Estar atento ao cache da CPU pode acelerar bastante as coisas - você só precisa prestar mais atenção a onde as coisas serão colocadas em relação à memória física e quando elas provavelmente serão usadas.

Um exemplo (também provavelmente um anti-padrão para manutenibilidade) é que você tem uma matriz de estruturas e você faz um monte de loops sobre os membros da estrutura que você pode ser melhor servido com uma estrutura onde os campos são todos os arrays. Se os dados que você está fazendo em loop forem contíguos na memória, você terá uma chance melhor de não perturbar o cache.

Todos os tipos de coisas podem afetar a eficiência do seu uso de cache - predição de ramo para código carregado no cache, tamanho e alinhamento de estruturas de dados e padrões de acesso, onde e quando declarar variáveis ​​locais que serão colocadas na pilha. 

O outro uso comum do termo para programação de aplicativos pode ser feito por algo chamado memoization . O exemplo fatorial na página da Wikipedia explica as coisas melhor do que eu teria feito.

2
Dave

O armazenamento em cache em bancos de dados é tipicamente uma função do banco de dados e é gerenciado automaticamente pelo banco de dados. O cache em aplicativos varia de uma plataforma para outra. 

Um cache de objetos é um mecanismo que você pode usar para colocar objetos comumente usados ​​na memória, para que você não precise pagar o custo para recuperar os dados e recriá-los. Isso geralmente é gerenciado por meio de código e varia em qual solução de cache você está usando.

Existem soluções de cache distribuído que envolvem a configuração de serviços em vários servidores para fornecer um tipo de farm de cache. Isso fornece escalabilidade e redundância. Os clientes podem solicitar as informações armazenadas em cache pela rede. Novamente, este é um procedimento manual em seu código. Um exemplo de um provedor de cache distribuído é o memcached:

http://www.danga.com/memcached/

Um exemplo de um tipo específico de armazenamento em cache seria o armazenamento em cache do asp.net. O asp.net suporta vários tipos de cache. Há o cache de objetos tradicional (que pode ser usado em todos os tipos de aplicativos .net, não apenas em sites). Há também recursos de cache que permitem configurar páginas e controles de usuário para armazenar automaticamente em cache sua saída. Isso não armazena em cache os dados, armazena em cache o resultado final (o HTML da página) e exibe quando o usuário solicita a mesma página com os mesmos parâmetros de string de consulta de um usuário anterior.

1
Jim Petkus

É provavelmente mais fácil do que você imagina - e é por isso que as pessoas estão tentando fechá-lo.

Significa apenas armazenar os valores em sua memória, em vez de voltar ao banco de dados para eles todas as vezes.

Existem muitas maneiras de fazê-lo, mas o conceito em si é trivial.

Edit: Isso pode ser feito em qualquer nível também - qualquer coisa que leva muito tempo pode ser armazenada em algum lugar que você pode chegar mais rapidamente.

0
Bill K

O armazenamento em cache não se aplica necessariamente apenas a valores "frequentemente recuperados", mas a qualquer coisa em que você economize tempo reduzindo o número de vezes que você o recompõe. Um exemplo simples que vem à mente é calcular a sequência fibonacci . A implementação recursiva mais simples se parece com isso (no código psuedo):

function f(n)
    if n < 2 then
        return n;
    return f(n - 1) + f(n - 2)

Isso pode ser melhorado com o armazenamento em cache para evitar o recálculo de valores já conhecidos:

fib_cache = {}

function f(n)
    if n < 2 then
        return n;
    if fib_cache.contains(n) then
        return fib_cache[n]
    fib_cache[n] = f(n - 1) + f(n - 2)
    return fib_cache[n]
0
Kevin Loney