1、redis中字符串类型的结构:
redis构建了一种名为简单动态字符串(simple dynamic string SDS)的数据抽象类型,默认字符串都是使用这种数据结构保存。整体结构如下:
struct sdshdr{
//记录buf数组中已使用的字节的数量,等于SDS所保存字符串的长度 int 占用四字节
int len;
//记录buf数组中未使用的字节数量 int占用4字节
int free;
//字节数组,用户保存字符串;
//为了表示字节数组的结束,Redis 会自动在数组最后加一个“\0”,
//这就会额外占用 1 个字节的开销。
char buf[];
}
a、String内存消耗如图所示:
redis有多个数据类型,不同数据类型都有一些相同的元数据需要记录(最后一次访问,被引用次数等)所有会有一个RedisObject的结构体记录这些数据,并指向实际数据。最终一个字符串除去本身实际字符串会多占用25个字节, 所以使用String类型有个比较明显的短板,内存开销比较大,容易产生大内存redis生产RDB导致响应变慢的问题。这个连接可以预估内存占用量: 内存预估b、String数据结构内存分布如图所示:
如果保存的字符串数据小于等于44字节,redisObject和SDS是一块连续的区域,可以避免内存碎片,被称为embstr编码方式;大于44字节就不会再布局到一起,被称为raw编码方式。
2、当面对大量String类型键值对需求如何优化空间分配(内存占用量超过2G得可以考虑)
可以使用集合类型保存这种类型的数据,具体举例如下:
可以采用Hash类型的二级编码方法,就是将一个单值的数据拆分成两部分,前一部分作为集合的key,后一部分作为Hash集合的value值中的key,这样可以将单值数据保存到Hash集合中,实例如下:
/**以图片 ID 1101000060 和图片存储对象 ID 3302000080 为例,
我们可以把图片 ID 的前 7 位(1101000)作为 Hash 类型的键,
把图片 ID 的最后 3 位(060)和
图片存储对象 ID 分别作为 Hash 类型值中的 key 和 value。*/
127.0.0.1:6379> info memory
# Memory
used_memory:1039120
127.0.0.1:6379> hset 1101000 060 3302000080
(integer) 1
127.0.0.1:6379> info memory
# Memory
used_memory:1039136
//使用了16个字节,而原本的直接以id为key,存储对象为值得需要64字节。
在使用Hash类型底层数据结构得时候,Hash会根据两个配置决定底层数据结构。为了充分使用压缩列表精简内存布局,就需要控制Hash集合中得元素个数,具体参数参考如下:
hash-max-ziplist-entries:表示用压缩列表保存时哈希集合中的最大元素个数。
hash-max-ziplist-value:表示用压缩列表保存时哈希集合中单个元素的最大长度。
如果在Hash集合中写入得元素个数超过hash-max-ziplist-entries或者单个元素大小超过hash-max-ziplist-value,redis就会自动把Hash的存储结构转换为哈希表。所以使用Hash要根据实际清空调整存入数据的单个长度和存入集合数据。