Pergunta

Eu criei um fórum, e estamos implementando um apc e memcache solução de cache para salvar o banco de dados de algum trabalho.

I começou a implementar a camada de cache com chaves como "Categorias :: getAll", e se eu tinha dados específicos do usuário, eu acrescentar as chaves com coisas como o ID do usuário, de modo que você deseja obter "User::getFavoriteThreads|1471". Quando um usuário adicionado um novo tópico favorito, eu excluir a chave do cache, e seria recriar a entrada.

No entanto, e aqui vem o problema:

Eu queria armazenar em cache os tópicos em um fórum. bastante simples, "Fórum :: getThreads | $ iForumId". Mas ... Com a paginação, eu teria que dividir isso em várias entradas de cache, por exemplo

"Forum::getThreads|$iForumId|$iLimit|$iOffset".

O que é certo, até que alguém postar um novo tópico no fórum. Agora vou ter que apagar todas as chaves sob "Forum::getThreads|$iForumId", não importa o que o limite e offset é.

O que seria uma boa maneira de resolver este problema? Eu realmente prefiro não passar por cada limite possível e compensar até eu encontrar algo que não corresponde mais.

Graças.

Foi útil?

Solução

Você também pode querer ter um olhar para o custo de armazenar os dados em cache, em termos de seu esforço e CPU custo, contra como o que o cache você vai comprar.

Se você achar que 80% de seus pontos de vista fórum está olhando para a primeira página de tópicos, então você pode decidir cache que página somente. Isso significaria tanto cache de leituras e gravações são muito mais simples de implment.

Da mesma forma com a lista de tópicos favoritos do usuário. Se isso é algo que cada pessoa visitas raramente, em seguida, o cache pode não melhorar o desempenho muito.

Outras dicas

Apenas uma atualização: Eu decidi que o ponto de Josh sobre o uso de dados era muito bom. As pessoas não são susceptíveis de manter a visitar a secção 50 de um fórum.

Com base neste modelo, decidi armazenar em cache os 90 mais recentes tópicos em cada fórum. Na função de buscar I verificar o limite e offset para ver se a fatia especificada de segmentos é dentro do cache ou não. Se estiver dentro do limite de cache, eu uso array_slice () para recuperar a parte direita e devolvê-lo.

Desta forma, posso usar uma única chave de cache por fórum, e leva muito pouco esforço para limpar / atualizar o cache: -)

Eu também gostaria de salientar que, em outras consultas pesados ??mais recursos, eu fui com o modelo de flungabunga, armazenar as relações entre chaves. Infelizmente Stack Overflow não me deixa aceitar duas respostas.

Obrigado!

Eu consegui resolver este estendendo a classe memcache com uma classe personalizada (dizem ExtendedMemcache) que tem uma propriedade protegida que irá conter uma tabela hash de grupo para valores de chave.

O método ExtendedMemcache->set aceita 3 argumentos ($strGroup, $strKey, $strValue) Quando você chama definido, ele irá armazenar o relacionamento entre $strGroup e $strKey, na propriedade protegida e, em seguida, ir para armazenar o $strKey a relação $strValue em memcache.

Você pode então adicionar um novo método para a classe ExtendedMemcache chamado "DeleteGroup", que irá, quando passou uma corda, encontrar que as chaves associadas a esse grupo, e limpar cada chave, por sua vez.

Seria algo como isto: http://pastebin.com/f566e913b Espero que tudo o que faz sentido e funciona para você.

PS. Suponho que se você quisesse usar chamadas estáticas a propriedade protegida poderiam ser salvas em memcache-se sob a sua própria chave. Apenas um pensamento.

Você está essencialmente tentando armazenar em cache uma visão, que é sempre vai ficar complicado. em vez disso você deve tentar apenas dados de cache, porque os dados raramente muda. Não armazenar em cache um fórum, armazenar em cache as linhas de rosca. Em seguida, a sua chamada db deve retornar apenas uma lista de ids, o que você já tem em seu cache. A chamada db será relâmpago rápido em qualquer tabela MyISAM, e então você não tem que fazer um grande juntar-se, que come db memória.

Uma possível solução é não paginar o cache de threads em um fórum, mas sim colocar a informação segmento em que Forum::getThreads|$iForumId. Então no seu código PHP só puxar para fora o que deseja para que determinada página, por exemplo.

$page = 2;
$threads_per_page = 25;
$start_thread = $page * $threads_per_page;

// Pull threads from cache (assuming $cache class for memcache interface..)
$threads = $cache->get("Forum::getThreads|$iForumId");

// Only take the ones we need
for($i=$start_thread; $i<=$start_thread+$threads_per_page; $i++)
{
    // Thread display logic here...
    showThread($threads[$i]);
}

Isto significa que você tem um pouco mais de trabalho para fazer puxá-los para fora em cada página, mas agora só tem que se preocupar invalidar o cache em um lugar na atualização / adição de novo segmento.

flungabunga: Sua solução é muito perto do que eu estou procurando. A única coisa me impedindo de fazer isso é ter que armazenar os relacionamentos em memcache depois de cada pedido e colocá-los de volta.

Eu não tenho certeza quanto de um desempenho acertar isso significaria, mas parece um pouco ineficiente. Vou fazer alguns testes e ver como ele garimpa para fora. Obrigado por uma sugestão estruturado (e algum código para mostrar para ele, graças!).

Tenha muito cuidado em fazer este tipo de otimização sem ter fatos concretos para medir contra.

A maioria dos bancos de dados têm vários níveis de caches. Se estes estão sintonizadas corretamente, o banco de dados provavelmente vai fazer um trabalho muito melhor em cache, do que você pode fazer o seu self.

Em resposta a flungabunga:

Outra forma de implementar agrupamento é colocar o nome do grupo de uma sequência para as próprias chaves e incrementar o número de seqüência para "limpar" o grupo. Você armazena o número de sequência válido atual para cada grupo em sua própria chave.

por exemplo.

get seqno_mygroup
23

get mygroup23_mykey
<mykeydata...>
get mygroup23_mykey2
<mykey2data...>

Em seguida, a "exclusão", o grupo simplesmente:

incr seqno_mygroup

Voila:

get seqno_mygroup
24

get mygroup24_mykey
...empty

etc ..

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top