我想将JSON有效负载存储到redis中 . 我有两种方法可以做到这一点:
- 使用简单的字符串键和值 .
key:user,value:payload(整个JSON blob,可以是100-200 KB)
SET user:1 payload
- 使用哈希
HSET user:1 username "someone" HSET user:1 location "NY" HSET user:1 bio "STRING WITH OVER 100 lines"
请记住,如果我使用哈希值,则值的长度是不可预测的 . 它们并非都是短的,例如上面的生物例子 .
哪个内存更有效?使用字符串键和值,还是使用哈希?
3 回答
这取决于您访问数据的方式:
选择方案1:
如果您在大多数访问中使用大多数字段 .
如果可能的键有差异
选择2:
如果您在大多数访问中仅使用单个字段 .
如果您始终知道哪些字段可用
P.S . :作为一个经验法则,请选择在大多数用例中需要较少查询的选项 .
这篇文章可以提供很多见解:http://redis.io/topics/memory-optimization
有很多方法可以在Redis中存储一个对象数组( spoiler :我喜欢大多数用例的选项1):
一般来说,这可能是大多数情况下最好的方法 . 如果对象中有很多字段,则对象不会与其他对象嵌套,并且您一次只能访问一小部分字段,最好选择选项2 .
Advantages :被认为是"good practice."每个对象都是一个完整的Redis密钥 . JSON解析很快,特别是当您需要同时访问此Object的许多字段时 . Disadvantages :只需访问单个字段时速度较慢 .
Advantages :被认为是"good practice."每个对象都是一个完整的Redis密钥 . 无需解析JSON字符串 . Disadvantages :当您需要访问Object中的所有/大多数字段时可能会更慢 . 此外,无法轻松存储嵌套对象(对象内的对象) .
这允许您合并一点,只使用两个键而不是许多键 . 明显的缺点是你不能在每个用户对象上设置TTL(和其他东西),因为它只是Redis哈希中的一个字段而不是一个完整的Redis密钥 .
Advantages :JSON解析速度很快,尤其是当您需要同时访问此Object的许多字段时 . 较少"polluting"的主键名称空间 . Disadvantages :当你有很多对象时,大约与#1相同的内存使用量 . 当您只需要访问单个字段时,比#2慢 . 可能不被认为是"good practice."
根据上面的文章,这个选项几乎从不首选(除非Object的属性需要特定的TTL或其他东西) .
Advantages :对象属性是完整的Redis密钥,对您的应用程序而言可能不会过度 . Disadvantages :慢,使用更多内存,而不考虑"best practice."主键名称空间有很多污染 .
总结
方案4通常不是优选的 . 选项1和2非常相似,它们都很常见 . 我更喜欢选项1(一般来说),因为它允许您存储更复杂的对象(具有多层嵌套等) . 当您真正关心不污染主键名称空间时使用选项3(即您不关心像TTL,关键字分片等等 .
如果我在这里遇到问题,请考虑发表评论并允许我在下注之前修改答案 . 谢谢! :)
对一组给定答案的一些补充:
首先,如果你要有效地使用Redis散列,你必须知道密钥数最大数和最大值 - 否则如果它们突破hash-max-ziplist-value或hash-max-ziplist-entries Redis会将它转换为实际引擎盖下的常用键/值对 . (请参阅hash-max-ziplist-value,hash-max-ziplist-entries)并且从哈希选项中打破引擎是非常糟糕的,因为Redis中的每个常用键/值对每对使用90个字节 .
这意味着如果你从选项2开始并意外地突破max-hash-ziplist-value,你将获得每个EACH ATTRIBUTE 90个字节,你有内部用户模型! (实际上不是90但是70见下面的控制台输出)
对于TheHippo的回答,对备选方案一的评论具有误导性:
如果你需要所有字段或多个get / set操作,hgetall / hmset / hmget来解救 .
对于BMiner的回答 .
第三个选项实际上非常有趣,对于具有max(id)<has-max-ziplist-value的数据集,此解决方案具有O(N)复杂度,因为,出乎意料的是,Reddis将小哈希存储为长度/键/值的类似数组的容器对象!
但是你不用担心,你会非常快地打破hash-max-ziplist-entries,而你现在实际上是在解决方案1号 .
第二个选项很可能会转到引擎盖下的第四个解决方案,因为问题表明:
正如您已经说过的那样:第四种解决方案是每个属性最昂贵的70字节 .
我建议如何优化这样的数据集:
你有两个选择:
如果你不能保证某些用户属性的最大大小比第一个解决方案更大,并且内存问题比在redis中存储之前压缩用户json至关重要 .
如果可以强制所有属性的最大大小 . 您可以设置hash-max-ziplist-entries / value,并将哈希值用作每个用户表示的一个哈希值或从Redis指南的主题中使用哈希内存优化:https://redis.io/topics/memory-optimization并将用户存储为json字符串 . 无论哪种方式,您还可以压缩长用户属性 .