Quero armazenar uma carga JSON em redis. Existem realmente duas maneiras de fazer isso:
Um usando chaves e valores simples de string.
key: user, value: payload (todo o blob JSON que pode ter entre 100 e 200 KB)SET user:1 payload
Usando hashes
HSET user:1 username "someone"
HSET user:1 location "NY"
HSET user:1 bio "STRING WITH OVER 100 lines"
Lembre-se de que, se eu usar um hash, o tamanho do valor não será previsível. Eles não são todos curtos, como o exemplo bio acima.
Qual é mais eficiente em termos de memória? Usando chaves e valores de string ou usando um hash?
Respostas:
Depende de como você acessa os dados:
Vá para a opção 1:
Vá para a opção 2:
PS: Como regra geral, escolha a opção que requer menos consultas na maioria dos seus casos de uso.
fonte
JSON
carga útil (um problema clássico de não atômicaread-modify-write
).Este artigo pode fornecer muitas informações aqui: http://redis.io/topics/memory-optimization
Existem várias maneiras de armazenar uma variedade de objetos no Redis ( spoiler : gosto da opção 1 na maioria dos casos de uso):
Armazene o objeto inteiro como uma string codificada em JSON em uma única chave e acompanhe todos os Objetos usando um conjunto (ou lista, se mais apropriado). Por exemplo:
De um modo geral, este é provavelmente o melhor método na maioria dos casos. Se houver muitos campos no Objeto, seus Objetos não estão aninhados com outros Objetos e você tende a acessar apenas um pequeno subconjunto de campos por vez, talvez seja melhor seguir a opção 2.
Vantagens : considerada uma "boa prática". Cada objeto é uma chave Redis completa. A análise JSON é rápida, especialmente quando você precisa acessar muitos campos para este Objeto de uma só vez. Desvantagens : mais lento quando você precisa acessar apenas um único campo.
Armazene as propriedades de cada objeto em um hash Redis.
Vantagens : considerada uma "boa prática". Cada objeto é uma chave Redis completa. Não há necessidade de analisar cadeias JSON. Desvantagens : possivelmente mais lento quando você precisar acessar todos / a maioria dos campos em um Objeto. Além disso, objetos aninhados (objetos dentro de objetos) não podem ser facilmente armazenados.
Armazene cada Objeto como uma sequência JSON em um hash Redis.
Isso permite que você consolide um pouco e use apenas duas chaves em vez de muitas chaves. A desvantagem óbvia é que você não pode definir o TTL (e outras coisas) em cada objeto de usuário, pois é apenas um campo no hash Redis e não uma chave Redis completa.
Vantagens : A análise JSON é rápida, especialmente quando você precisa acessar muitos campos para este Objeto de uma só vez. Menos "poluidor" do espaço para nome da chave principal. Desvantagens : Sobre o mesmo uso de memória que o nº 1, quando você tem muitos objetos. Mais lento que o número 2 quando você precisa acessar apenas um único campo. Provavelmente não é considerado uma "boa prática".
Armazene cada propriedade de cada objeto em uma chave dedicada.
De acordo com o artigo acima, essa opção quase nunca é preferida (a menos que a propriedade do objeto precise ter TTL específico ou algo assim).
Vantagens : as propriedades do objeto são chaves Redis completas, que podem não ser um exagero para o seu aplicativo. Desvantagens : lento, usa mais memória e não é considerado "melhor prática". Muitos poluidores do espaço para nome da chave principal.
Resumo geral
A opção 4 geralmente não é preferida. As opções 1 e 2 são muito semelhantes e são bastante comuns. Prefiro a opção 1 (de modo geral) porque permite armazenar objetos mais complicados (com várias camadas de aninhamento, etc.) A opção 3 é usada quando você realmente se preocupa em não poluir o espaço para nome da chave principal (ou seja, você não deseja ter muitas chaves em seu banco de dados e você não se importa com coisas como TTL, compartilhamento de chaves ou qualquer outra coisa).
Se eu entendi algo errado aqui, considere deixar um comentário e me permita revisar a resposta antes da votação. Obrigado! :)
fonte
obj
e armazenamos campos como visualizações, votos e eleitores com chaves separadas? Dessa forma, com uma única consulta READ, você obtém o objeto inteiro e ainda pode atualizar partes dinâmicas do seu objeto rapidamente? As atualizações relativamente infreqüentes dos campos na cadeia JSON podem ser feitas lendo e gravando o objeto inteiro novamente em uma transação.Algumas adições a um determinado conjunto de respostas:
Antes de tudo, se você usar o hash Redis de maneira eficiente, deverá saber que as teclas contam número máximo e valores tamanho máximo - caso contrário, se elas quebrarem as entradas hash-max-ziplist-value ou hash-max-ziplist-redis, o Redis o converterá em praticamente pares chave / valor usuais sob um capô. (consulte as entradas hash-max-ziplist, hash-max-ziplist) E quebrar sob o capô de uma opção de hash É MUITO RUIM, porque cada par de chave / valor usual dentro do Redis usa +90 bytes por par.
Isso significa que, se você começar com a opção dois e acidentalmente romper o valor de max-hash-ziplist, receberá +90 bytes por CADA ATRIBUTO que tiver dentro do modelo do usuário! (na verdade, não os +90, mas +70, veja a saída do console abaixo)
Para a resposta TheHippo, os comentários sobre a opção um são enganosos:
hgetall / hmset / hmget para o resgate, se você precisar de todos os campos ou de várias operações get / set.
Para resposta BMiner.
A terceira opção é realmente muito divertida, para um conjunto de dados com valor máximo (id) <has-max-ziplist-value, esta solução possui complexidade O (N), porque, surpresa, o Reddis armazena pequenos hashes como contêineres de comprimento / chave / valor em forma de matriz objetos!
Mas não se preocupe, você quebrará as entradas hash-max-ziplist muito rápido e lá está você agora na solução número 1.
A segunda opção provavelmente irá para a quarta solução, porque, como afirma a pergunta:
E como você já disse: a quarta solução é o mais caro +70 bytes por cada atributo, com certeza.
Minha sugestão de como otimizar esse conjunto de dados:
Você tem duas opções:
Se você não puder garantir o tamanho máximo de alguns atributos do usuário, procure a primeira solução e se a questão da memória for crucial, comprima o usuário json antes de armazenar em redis.
Se você pode forçar o tamanho máximo de todos os atributos. Você pode definir hash-max-ziplist-entradas / valor e usar hashes como um hash por representação do usuário OU como otimização de memória de hash neste tópico de um guia Redis: https://redis.io/topics/memory-optimization e armazenar usuário como string json. De qualquer forma, você também pode compactar atributos de usuário longos.
fonte