我想把一个JSON有效载荷存储到redis中,有两种方法可以做到:
1.一个使用简单的字符串键和值。
键:用户,值:有效负载(整个JSON blob,大小可以是100-200 KB)
第一个月
1.使用散列HSET user:1 username "someone" HSET user:1 location "NY" HSET user:1 bio "STRING WITH OVER 100 lines"
请记住,如果我使用散列,值的长度是不可预测的。它们并不都像上面的生物示例那样短。
哪一种内存效率更高?使用字符串键和值,还是使用哈希?
6条答案
按热度按时间4nkexdtk1#
这篇文章可以提供很多见解:http://redis.io/topics/memory-optimization
在Redis中有很多方法可以存储对象数组(spoiler:对于大多数使用情形,我喜欢选项1):
1.将整个对象作为JSON编码的字符串存储在单个键中,并使用集合(或列表,如果更合适)跟踪所有对象。例如:
一般来说,这可能是大多数情况下最好的方法。如果对象中有很多字段,您的对象没有与其他对象嵌套,并且您倾向于一次只访问字段的一个小子集,那么选择2可能更好。
1.将每个对象的属性存储在Redis散列中。
1.将每个对象存储为Redis散列中的JSON字符串。
这允许你合并一点,只使用两个密钥而不是很多密钥。明显的缺点是你不能在每个用户对象上设置TTL(和其他东西),因为它只是Redis哈希中的一个字段,而不是一个完整的Redis密钥。
1.将每个对象的每个属性存储在专用键中。
根据上面的文章,这个选项 * 几乎从不 * 是首选的(除非Object的属性需要具有特定的TTL或其他属性)。
总体总结
选项4一般不可取。选项1和选项2非常相似,都很常见。我更喜欢选项1(一般来说),因为它允许您存储更复杂的对象(利用多层嵌套,等)选项3在您 * 真正关心 * 不污染主键名称空间时使用(也就是说,您不希望数据库中有很多密钥,也不关心TTL、密钥分片等问题)。
如果我在这里做错了什么,请考虑留下评论,并允许我在下投之前修改答案。谢谢!:)
hmtdttj42#
这取决于您访问数据的方式:
选择选项1:
选择选项2:
P.S.:作为一个经验法则,在大多数用例中,选择需要较少查询的选项。
332nm8kg3#
对给定答案的一些补充:
首先,如果你想有效地使用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,你将在用户模型中得到每个属性+90字节!(实际上不是+90而是+70,参见下面的控制台输出)
对于TheHippo的回答,对选项一的评论具有误导性:
如果需要所有字段或多个get/set操作,请使用hgetall/hmset/hmget进行救援。
对于BMiner的回答。
第三个选项实际上非常有趣,对于max(id)〈has-max-ziplist-value的数据集,这个解决方案有O(N)的复杂度,因为令人惊讶的是,Reddis将小哈希存储为类似数组的长度/键/值对象的容器!
但是很多时候散列只包含几个字段,当散列很小时,我们可以用O(N)的数据结构来编码它们,就像一个带有长度前缀的键值对的线性数组,因为我们只在N很小时才这样做,所以HGET和HSET命令的摊余时间仍然是O(1):一旦散列表包含的元素数量增长太多,散列表就会被转换成真实的散列表
但是你不用担心,你会很快打破hash-max-ziplist-entries,现在你实际上已经到了第一个解决方案。
第二种选择很可能会在幕后使用第四种解决方案,因为正如问题所述:
请记住,如果我使用散列,值的长度是不可预测的。它们并不都像上面的生物示例那样短。
就像你说的:第四种解决方案肯定是每个属性最昂贵的+70字节。
我的建议如何优化这样的数据集:
你有两个选择:
1.如果你不能保证一些用户属性的最大大小,那么你会选择第一个解决方案,如果内存问题很重要,那么在存储到redis之前压缩用户json。
1.如果你可以强制所有属性的最大值,那么你可以设置hash-max-ziplist-entries/value,并将哈希值作为每个用户表示的一个哈希值,或者作为哈希内存的优化。https://redis.io/topics/memory-optimization并将用户存储为json字符串。无论哪种方式,您都可以压缩长用户属性。
tzdcorbm4#
我们在生产环境中遇到了类似的问题,我们提出了一个想法,即如果负载超过某个阈值KB,则对负载进行gzip压缩。
我有一个专用于这个Redis客户端库here的存储库
其基本思想是如果有效载荷的大小大于某个阈值则检测该有效载荷,然后将其以及base-64进行Gzip压缩,然后将压缩后的串作为正常串保存在REDIS中。在检索时检测该串是否是有效的base-64串,如果是,则将其解压缩。
整个压缩和解压缩过程将是透明的,而且您可以获得接近50%的网络流量
压缩基准测试结果
| 方法|平均值|错误|标准差|第0代|第1代|第2代|已分配|
| - ------| - ------| - ------| - ------| - ------| - ------| - ------| - ------|
| 压缩基准|668.2毫秒|十三点三四毫秒|二十七点二四毫秒|- -| - -| - -| 4.88兆字节|
| 无压缩基准|1,387.1毫秒|二十六点九二毫秒|37.74毫秒|- -| - -| - -| 2.39兆字节|
crcmnpdw5#
要在Redis中存储JSON,您可以使用Redis JSON模块。
这将为您提供:
https://redis.io/docs/stack/json/
https://developer.redis.com/howtos/redisjson/getting-started/
https://redis.com/blog/redisjson-public-preview-performance-benchmarking/
jk9hmnmh6#
您可以使用json模块:https://redis.io/docs/stack/json/它是完全支持的,允许你在Redis中使用json作为数据结构。Redis也有一些语言的对象Map器:https://redis.io/docs/stack/get-started/tutorials/