Redis使用字符串和hash存储JSON,那个更高效?

最近在排查一个线上问题,发现redis使用了一个hash key里面存储了600w的field,为啥这么多就是因为他把一个结构体中的字段分成了多个field存储。下面来看看到底应该怎么设计比较合理。

一、问题

  1. 一种使用简单的字符串键和值。
    键:用户,值:payload(整个JSON,可以为100-200 KB)
SET user:1 payload
  1. 使用哈希
HSET user:1 username "someone" 
HSET user:1 location "NY" 
HSET user:1 bio "STRING WITH OVER 100 lines"

请记住,如果使用哈希,则值长度是不可预测的。它们并不都是短的,例如上面的bio示例。哪个内存效率更高?使用字符串键和值,还是使用哈希?

二、讨论

  1. 将整个对象作为JSON编码的字符串存储在单个键中,并使用一组(或列表,如果合适的话)跟踪所有对象。例如:
INCR id:users
SET user:{id} '{"name":"Fred","age":25}'
SADD users {id}

一般来说,在大多数情况下,这可能是最好的方法。如果对象中有很多字段,一个对象不会与其他对象嵌套,并且您一次只能访问一小部分字段,那么选择选项1可能不是很好。

优点:被认为是“良好实践”。每个对象都是具有用户信息的Redis key。JSON解析速度很快,尤其是当您需要一次访问此Object的多个字段时。

缺点:当您只需要访问一个字段时,速度较慢。

  1. 将每个对象的属性存储在Redis哈希中。
INCR id:users
HMSET user:{id} name "Fred" age 25
SADD users {id}

优点:被认为是“良好实践”。每个对象都是具有用户信息的Redis key。无需解析JSON字符串。

缺点:当您需要访问对象中的所有/大多数字段时,速度可能会变慢。同样,嵌套对象(对象内的对象)也无法轻松存储。

  1. 将每个对象作为JSON字符串存储在Redis哈希中。
INCR id:users
HMSET users {id} '{"name":"Fred","age":25}'

这使您可以进行合并,并且仅使用两个键,而不是很多键。明显的缺点是您不能在每个用户对象上设置TTL(以及其他内容),因为它只是Redis哈希中的一个字段,而不是具有用户信息的Redis key。

优点:JSON解析速度很快,尤其是当您需要一次访问此Object的多个字段时。减少主键名称空间的“污染”。

缺点:当您有很多对象时,内存使用量与#1差不多。当您只需要访问单个字段时,速度比#2慢。可能不被视为“良好做法”。

  1. 将每个对象的每个属性存储在专用key中。
INCR id:users
SET user:{id}:name "Fred"
SET user:{id}:age 25
SADD users {id}

根据上面的解释,几乎永远不会选择此方案(除非Object的属性需要具有特定的TTL或其他内容)。

优点:对象属性是具有用户信息的Redis key,对于您的应用程序来说可能并不算过大。

缺点:速度慢,占用更多内存,并且不被视为“最佳实践”。主键名称空间受到很多污染。

三、总结

方案4通常不是首选。方案1和2非常相似,而且都很常见。我更喜欢选项1(通常来说),因为它允许您存储更复杂的对象(具有多层嵌套等)。当您真正关心不污染主键名称空间时,可以使用方案3。

GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e 2 个月前
8c391e04 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐