Groupcache: Prática recomendada para atualizar uma entrada de cache com freqüência

Criado em 8 mar. 2015  ·  9Comentários  ·  Fonte: golang/groupcache

Minha pergunta é um pouco semelhante ao problema https://github.com/golang/groupcache/issues/3.

Eu tenho um mapa que atualmente é gerenciado na RAM do aplicativo go em uma única instância. Quero compartilhar este mapa entre várias instâncias para dimensionamento. Já estou usando o consul para descoberta de instâncias de peer e atualmente estou resolvendo isso com o redis, no entanto, não estou feliz com o fato de não estar aproveitando a RAM de cada máquina (então, nesse sentido, sinto que o redis é mais um banco de dados do que um cache). Este é um dos motivos pelos quais adoro groupcache.

No entanto, tenho uma restrição: meu mapa muda o tempo todo (estou recebendo solicitações para atualizá-lo via http). Portanto, para uma chave K1 no mapa, é provável que m [K1] seja atualizado com muita frequência (possivelmente a cada segundo ou menos).

Então, minhas perguntas são:

  1. Estou escolhendo a arquitetura errada? Devo usar algo como Redis ou memecached em vez disso?
  2. Se o groupcache for uma boa solução para meu caso de uso, tenho que remover e adicionar constantemente (digamos em um cache LRU) ou existe uma maneira mais inteligente?

Obrigado!

Comentários muito úteis

Ei, @orcaman. Sou apenas mais um usuário do Groupcache, mas espero poder responder à sua pergunta.

Em primeiro lugar, as duas coisas mais importantes a lembrar são que o Groupcache é um cache somente leitura, o que significa que você não pode atualizar as chaves nele. e segundo, que os dados são considerados imutáveis ​​e não expiram. É basicamente apenas um LRU distribuído. Portanto, se você precisa atualizar as chaves com frequência, o GC não é uma boa opção.

No entanto, você pode emular a expiração ou alteração de dados existentes por manipulação de chave.

No meu caso, precisei expirar cerca de uma hora para as chaves. O que fiz foi adicionar o carimbo de data / hora da próxima hora da rodada a qualquer chave que estou tentando obter. Assim, quando uma hora passa, essa parte da chave do meu aplicativo está solicitando alterações e, do ponto de vista do Groupcache, estou pedindo uma nova chave. O antigo será despejado por meio do mecanismo LRU, pois ninguém mais o tocará.

Mas se você precisar escrever chaves constantemente e expirar na segunda resolução, será melhor usar o redis ou o memcache. Eu escolheria memcache porque é mais fácil de escalar com mais servidores.

Todos 9 comentários

Ei, @orcaman. Sou apenas mais um usuário do Groupcache, mas espero poder responder à sua pergunta.

Em primeiro lugar, as duas coisas mais importantes a lembrar são que o Groupcache é um cache somente leitura, o que significa que você não pode atualizar as chaves nele. e segundo, que os dados são considerados imutáveis ​​e não expiram. É basicamente apenas um LRU distribuído. Portanto, se você precisa atualizar as chaves com frequência, o GC não é uma boa opção.

No entanto, você pode emular a expiração ou alteração de dados existentes por manipulação de chave.

No meu caso, precisei expirar cerca de uma hora para as chaves. O que fiz foi adicionar o carimbo de data / hora da próxima hora da rodada a qualquer chave que estou tentando obter. Assim, quando uma hora passa, essa parte da chave do meu aplicativo está solicitando alterações e, do ponto de vista do Groupcache, estou pedindo uma nova chave. O antigo será despejado por meio do mecanismo LRU, pois ninguém mais o tocará.

Mas se você precisar escrever chaves constantemente e expirar na segunda resolução, será melhor usar o redis ou o memcache. Eu escolheria memcache porque é mais fácil de escalar com mais servidores.

Obrigado @dvirsky !
Acho que entendi.

Sem problemas, embora eu estivesse meio que esperando por mais adoção do Groupcache na cena israelense. Você conhece outras empresas que o utilizam? :)

Podemos ainda usá-lo, apenas esperando o caso de uso certo. :-)
Não conheço muitos esquilos na cena israelense, então não saberia sobre os usuários do Groupcache. Estou ansioso para conhecê-lo no encontro go meetup (se você vier, isto é).

Legal. Estamos usando-o como um cache HTTP de saída (ou seja, solicitações de cache que estamos fazendo a terceiros). Podemos abrir esta implementação algum dia.
Não tenho certeza sobre o encontro Go, espero conseguir.

@dvirsky e @bradfitz - No meu caso de uso, gostaria de lidar com TTL [planejando adicionar o carimbo de data / hora da hora atual à chave]. Tenho as seguintes perguntas,

1.Como o mecanismo LRU remove a chave. Podemos definir a duração mínima em que a chave não é usada [para marcá-la como expirada]?
2.Se não, isso depende da memória alocada para o cache. Quando os dados excederem o alocado, os menos usados ​​recentemente serão removidos? Nesse caso, como podemos lidar com o equilíbrio da memória para não remover os dados da hora atual?

Você poderia dar algumas sugestões para isso?

@dvirsky Obrigado por sua ótima resposta. No entanto, você vê um pequeno pico de CPU e memória a cada hora quando os itens são "despejados" ao mesmo tempo?

@qbig depende de como você implementou a expiração. Aqui está o que eu fiz:

// turn a ttl into an expiration timestamp, using discrete time windows.
// i.e. ask for an hour and get the nearest hour end as the expiration point.
//
// We pad these discrete boundaries  pseudo random margin (based on hashing the key)
// to avoid hitting the cache too hard if all requests expire at once
//
// This can be seconds from now even if you cache for days :)
func calcExpiration(ttl int64, key string, now int64) int64 {
    //we calculate the non discrete expiration, relative to current time
    expires := now

    var padding int64 = 0
    if ttl > 0 {
        // now we want to pad it so we'll no expire all reqeusts for a given time window at once
        // to be consistent, the seed of the padding is a hash on the url
        h := fnv.New32a()
        h.Write([]byte(key))
        padding = int64(h.Sum32()) % ttl

               // not sure this is correct - I wrote it long ago :)
        expires += (ttl - (expires % ttl)) - padding
        if expires < now {
            expires += ttl
        }

    }

    return expires

}

@orcaman dê uma olhada em https://tarantool.org/

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

cowboyrushforth picture cowboyrushforth  ·  5Comentários

yml picture yml  ·  3Comentários

abennett picture abennett  ·  3Comentários

AlexanderChen1989 picture AlexanderChen1989  ·  6Comentários

noahwhite picture noahwhite  ·  3Comentários