网站首页 > 技术文章 正文
看到一个问题, Redis strings vs Redis hashes to represent JSON: efficiency? 内容如下:
I want to store a JSON payload into redis. There's really 2 ways I can do this:
- One using a simple string keys and values.
- key:user, value:payload (the entire JSON blob which can be 100-200 KB)
- SET user:1 payload
- Using hashes
- HSET user:1 username "someone"
- HSET user:1 location "NY"
- HSET user:1 bio "STRING WITH OVER 100 lines"
Keep in mind that if I use a hash, the value length isn't predictable. They're not all short such as the bio example above.
Which is more memory efficient? Using string keys and values, or using a hash?
string 和 hash 直观测试
首先我们先测试用数据测试一下,测试数据结构如下:
values = { "name": "gs", "age": 1 }
使用for 生成10w个key,key的生成规则为:
for i in range(100000): key = "object:%d" % i
把数据分别以hash 和 string(values 使用 json encode 为string )的形式存入redis。
结果如下:
hash 占用 10.15M
这看起来和我们印象中hash 占空间比较大的观念不太一致,这是为什么呢?
这里是因为Redis 的hash 对象有两种编码方式:
- ziplist(2.6之前是zipmap)
- hashtable
当哈希对象可以同时满足以下两个条件时, 哈希对象使用 ziplist 编码:
- 哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节;
- 哈希对象保存的键值对数量小于 512 个;
不能满足这两个条件的哈希对象需要使用 hashtable 编码。上述测试数据满足这两个条件,所以这里使用的是ziplist来存储的数据,而不是hashtable。
注意
这两个条件的上限值是可以修改的, 具体请看配置文件中关于 hash-max-ziplist-value 选项和 hash-max-ziplist-entries 选项的说明。
hash-max-ziplist-entries for Redis >= 2.6
hash-max-ziplist-value for Redis >= 2.6
ziplist
ziplist 编码的数据底层是使用压缩列表作为底层数据结构,结构如下:
hash 对象使用ziplist 保存时,程序会将保存了键的ziplist节点推入到列表的表尾,然后再将保存了值的ziplist节点推入列表的表尾。
使用这种方式保存时,并不需要申请多余的内存空间,而且每个Key都要存储一些关联的系统信息(如过期时间、LRU等),因此和String类型的Key/Value相比,Hash类型极大的减少了Key的数量(大部分的Key都以Hash字段的形式表示并存储了),从而进一步优化了存储空间的使用效率。
在这篇 redis memory optimization 官方文章中,作者强烈推荐使用hash存储数据
Use hashes when possible
Small hashes are encoded in a very small space, so you should try representing your data using hashes every time it is possible. For instance if you have objects representing users in a web application, instead of using different keys for name, surname, email, password, use a single hash with all the required fields.
But many times hashes contain just a few fields. When hashes are small we can instead just encode them in an O(N) data structure, like a linear array with length-prefixed key value pairs. Since we do this only when N is small, the amortized time for HGET and HSET commands is still O(1): the hash will be converted into a real hash table as soon as the number of elements it contains will grow too much (you can configure the limit in redis.conf).
This does not work well just from the point of view of time complexity, but also from the point of view of constant times, since a linear array of key value pairs happens to play very well with the CPU cache (it has a better cache locality than a hash table).
hashtable
hashtable 编码的哈希对象使用字典作为底层实现, 哈希对象中的每个键值对都使用一个字典键值对来保存:
- 字典的每个键都是一个字符串对象, 对象中保存了键值对的键;
- 字典的每个值都是一个字符串对象, 对象中保存了键值对的值。
hashtable 编码的对象如下所示:
第二次测试
values = { "name": "gs", "age": 1, "intro": "long..long..long..string" }
第二次测试方式和第一次一样,只是把测试数据中加了一个大的字符串,以保证hash 使用hashtable 的方式存储数据
结果如下:
string: 1.13G
基本一样,这里应该主要是Hash类型极大的减少了Key的数量(大部分的Key都以Hash字段的形式表示并存储了),从而进一步优化了存储空间的使用效率。
NOTE:读取和写入的速度基本一致,差别不大
回到这个问题,对于string 和 hash 该如何选择呢?
我比较赞同下面这个答案:
具体使用哪种数据结构,其实是需要看你要存储的数据以及使用场景。
如果存储的都是比较结构化的数据,比如用户数据缓存,或者经常需要操作数据的一个或者几个,特别是如果一个数据中如果filed比较多,但是每次只需要使用其中的一个或者少数的几个,使用hash是一个好的选择,因为它提供了hget 和 hmget,而无需取出所有数据再在代码中处理。
反之,如果数据差异较大,操作时常常需要把所有数据都读取出来再处理,使用string 是一个好的选择。
当然,也可以听Redis 的,放心的使用hash 吧。
还有一种场景:如果一个hash中有大量的field(成千上万个),需要考虑是不是使用string来分开存储是不是更好的选择。
欢迎工作一到五年的Java工程师朋友们加入Java程序员开发: 721575865
群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!
- 上一篇: 特征工程:基于梯度提升模型的特征编码效果测试
- 下一篇: Java高级面试之哈希表 哈希表java实现
猜你喜欢
- 2024-10-12 百度 面试题——Redis的对象类型与内部编码
- 2024-10-12 五分钟带你了解哈希算法究竟是什么!
- 2024-10-12 Redis哈希类型的使用场景 redis哈希槽的概念
- 2024-10-12 Redis哈希类型使用命令 redis 哈希操作
- 2024-10-12 对象存储服务器Minio(超详细) 对象存储服务适于哪些场景
- 2024-10-12 基于Vision Transformer的视频哈希检索识别虚假视频
- 2024-10-12 Java高级面试之哈希表 哈希表java实现
- 2024-10-12 特征工程:基于梯度提升模型的特征编码效果测试
- 2024-10-12 Redis 讲解系列之 Redis的五大数据类型和配置文件解读
- 2024-10-12 Redis 哈希表 VS Java HaspMap , 哪家强?
你 发表评论:
欢迎- 最近发表
-
- 在 Spring Boot 项目中使用 activiti
- 开箱即用-activiti流程引擎(active 流程引擎)
- 在springBoot项目中整合使用activiti
- activiti中的网关是干什么的?(activiti包含网关)
- SpringBoot集成工作流Activiti(完整源码和配套文档)
- Activiti工作流介绍及使用(activiti工作流会签)
- SpringBoot集成工作流Activiti(实际项目演示)
- activiti工作流引擎(activiti工作流引擎怎么用)
- 工作流Activiti初体验及在数据库中生成的表
- Activiti工作流浅析(activiti6.0工作流引擎深度解析)
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)