Redis的字符串VS Redis的哈希值来表示JSON:效率?Redis的字符串VS Redis的

2019-05-12 11:42发布

我想一个JSON有效载荷存储到Redis的。 这确实2点的方法,我可以这样做:

  1. 用一个简单的字符串键和值。
    键:用户,值:有效载荷(其全部JSON团块,其可以是100-200 KB)

    SET user:1 payload

  2. 使用哈希

    HSET user:1 username "someone"
    HSET user:1 location "NY"
    HSET user:1 bio "STRING WITH OVER 100 lines"

请记住,如果我使用的哈希,值长度是不可预测的。 他们是不是所有的短,如上面的例子生物。

这是更多的内存效率? 使用字符串键和值,或者使用哈希?

Answer 1:

这取决于你如何访问数据:

去选项1:

  • 如果您最常使用的领域上大部分的访问的。
  • 如果有可能的键方差

去选项2:

  • 如果您使用大部分的访问的只是单一的领域。
  • 如果你总是知道哪些字段可用

PS:作为一个经验法则,去为这需要对大多数的用例更少的查询选项。



Answer 2:

:本文可以在这里提供了很多有识之士的http://redis.io/topics/memory-optimization

有许多方法来存储对象的数组中的Redis( 扰流板 :我想对于大多数使用情况选择1):

  1. 存储整个对象作为JSON编码字符串在一个单一的关键和跟踪使用一组所有对象(或列表,如果更合适)。 例如:

     INCR id:users SET user:{id} '{"name":"Fred","age":25}' SADD users {id} 

    一般来说,这可能是在大多数情况下的最佳方法。 如果有很多的对象字段,你的对象是没有嵌套其他对象,你会一次只访问领域的一小部分,它可能是更好的去与选项2。

    优点 :认为是一个“很好的做法。” 每个对象都是一个完全成熟的Redis的关键。 JSON解析速度快,尤其是当你需要同时访问多个领域此对象。 缺点 :速度较慢时,你只需要访问一个字段。

  2. 在Redis的哈希存储中每个对象的属性。

     INCR id:users HMSET user:{id} name "Fred" age 25 SADD users {id} 

    优点 :认为是一个“很好的做法。” 每个对象都是一个完全成熟的Redis的关键。 无需解析JSON字符串。 缺点 :当你需要访问所有可能较慢/最对象的字段。 此外,嵌套对象(对象内的对象)不能被容易地存储。

  3. 存储每个对象为在Redis的哈希一个JSON字符串。

     INCR id:users HMSET users {id} '{"name":"Fred","age":25}' 

    这可以让你巩固一下,只用两个键来代替大量的密钥。 最明显的缺点是,你不能设置在每个用户对象的TTL(和其他的东西),因为它仅仅是在Redis的哈希一个领域,而不是一个完全成熟的Redis的关键。

    优点 :JSON解析速度快,尤其是当你需要同时访问多个领域此对象。 少主键命名空间的“污染”。 缺点 :关于相同的内存使用#1,当你有大量的对象。 比#2慢时,你只需要访问一个字段。 可能不被认为是“好习惯”。

  4. 存放在一个专门的键中的每个对象的每个属性。

     INCR id:users SET user:{id}:name "Fred" SET user:{id}:age 25 SADD users {id} 

    根据上面的文章,此选项几乎从不首选(除非对象的属性需要有具体的TTL或东西)。

    优点 :对象属性是完全成熟的Redis键,这可能不是矫枉过正为您的应用程序。 缺点 :速度慢,使用更多的内存,并且不被认为是“最佳实践”。 很多主键命名空间的污染的。

总体摘要

选项4通常不是优选的。 选项1和2是非常相似,他们都是很常见的。 我宁愿选择1(一般来说),因为它可以让你存储更多复杂的对象(与嵌套等的多层)选项3用于当你真正关心的不是污染的主要关键命名空间(即你不希望有是很多在数据库中键,你不关心的事情,如TTL,关键分片,或其他)。

如果我得到了什么在这里,请考虑留下评论文章,让我downvoting之前修改了答案。 谢谢! :)



Answer 3:

一些附加一组给定的答案:

首先,如果你打算使用Redis的哈希有效,你必须知道一键计数最大数量和价值最大尺寸 - 否则,如果他们打出来的哈希-MAX-ziplist值或哈希-MAX-ziplist条目Redis的将其转换为实际一个罩下通常键/值对。 (见散列-MAX-ziplist值,散列-MAX-ziplist条目),并从哈希选项的发动机罩下的断裂是非常糟糕,因为内部的Redis每个通常键/值对使用每对90个字节。

这意味着,如果你开始与方案二,不小心打破了MAX-哈希ziplist值的你会得到+90字节每每个属性你有用户模型里面! (其实并不是+90,但+ 70,请查看控制台下方输出)

 # you need me-redis and awesome-print gems to run exact code
 redis = Redis.include(MeRedis).configure( hash_max_ziplist_value: 64, hash_max_ziplist_entries: 512 ).new 
  => #<Redis client v4.0.1 for redis://127.0.0.1:6379/0> 
 > redis.flushdb
  => "OK" 
 > ap redis.info(:memory)
    {
                "used_memory" => "529512",
          **"used_memory_human" => "517.10K"**,
            ....
    }
  => nil 
 # me_set( 't:i' ... ) same as hset( 't:i/512', i % 512 ... )    
 # txt is some english fictionary book around 56K length, 
 # so we just take some random 63-symbols string from it 
 > redis.pipelined{ 10000.times{ |i| redis.me_set( "t:#{i}", txt[rand(50000), 63] ) } }; :done
 => :done 
 > ap redis.info(:memory)
  {
               "used_memory" => "1251944",
         **"used_memory_human" => "1.19M"**, # ~ 72b per key/value
            .....
  }
  > redis.flushdb
  => "OK" 
  # setting **only one value** +1 byte per hash of 512 values equal to set them all +1 byte 
  > redis.pipelined{ 10000.times{ |i| redis.me_set( "t:#{i}", txt[rand(50000), i % 512 == 0 ? 65 : 63] ) } }; :done 
  > ap redis.info(:memory)
   {
               "used_memory" => "1876064",
         "used_memory_human" => "1.79M",   # ~ 134 bytes per pair  
          ....
   }
    redis.pipelined{ 10000.times{ |i| redis.set( "t:#{i}", txt[rand(50000), 65] ) } };
    ap redis.info(:memory)
    {
             "used_memory" => "2262312",
          "used_memory_human" => "2.16M", #~155 byte per pair i.e. +90 bytes    
           ....
    }

对于TheHippo答案,方案一的评论是误导:

hgetall / hmset / hmget救援,如果你需要的所有字段或多个的get / set操作。

对于BMiner答案。

第三选项实际上是非常有趣的,对于具有最大(ID)的数据集<具有-MAX-ziplist值该解决方案具有O(N)的复杂性,因为,惊奇,Reddis商店小散列作为长度/键/值的阵列状容器对象!

但是很多时候散列只包含几个字段。 当散列小我们可以代替刚刚编码它们在O(N)的数据结构,像长度前缀密钥值对的线性阵列。 因为我们这样做,只有当N较小,摊销时间HGET和HSET命令仍然是O(1):哈希将尽快转化为真正的哈希表,因为它包含将增长过多的元素个数

但你不应该担心,你会打破哈希-MAX-ziplist条目非常快,你去那里你现在实际上是在解决1号。

第二个选择将最有可能去的第四个解决方案引擎盖下因为问题指出:

请记住,如果我使用的哈希,值长度是不可预测的。 他们是不是所有的短,如上面的例子生物。

正如你所说的:第四个解决方案是肯定的每每个属性最贵+ 70字节。

我的建议如何优化这样的数据集:

你有两个选择:

  1. 如果你不能保证一些用户的最大尺寸属性中的除你去第一个解决方案,如果内存不管是不是在Redis的存储之前压缩用户JSON是至关重要的。

  2. 如果你能迫使所有属性的最大尺寸。 比你可以设置散列-MAX-ziplist条目/值和使用哈希无论是作为每个用户表示或为从Redis的引导这个话题哈希内存优化一个哈希: https://redis.io/topics/memory-optimization和存储用户的JSON字符串。 无论哪种方式,你还可以压缩长的用户属性。



文章来源: Redis strings vs Redis hashes to represent JSON: efficiency?
标签: json redis