Redis Source Code Read Log( 8 hash )

Part 1: Redis hash 内部实现方式的选择与切换

Redis在redis.conf中提供了hash内部数据结构切换的条件

如下:

# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash-max-ziplist-entries 512
hash-max-ziplist-value 64

第一: entries 个数,需要低于 512 个。

第二: field 或者 string 类型的 value,长度必须小于或等于64(从ziplist内部实现的角度来看,不要等于64,小于64最好,这样encoding字段能够低位6bit可以直接指示出这一个entry的长度)

默认的,hash类型的内部会直接采用 ziplist 作为首选的存储结构。field 与 value 值分别作为两个前后相连的entry从尾部插入到现有的ziplist中。这样,插入的复杂度就是0(1)。

每次HSET操作时,都会触发检查过程。

检查条件:

1. field 或者 value(value必须是string的情况)值长度超过了 hash-max-ziplist-value 配置(默认64)。

2. ziplist中存储的field-value pair 对 超过了 hash-max-ziplist-entries 配置(默认512)。注意,field-value 一个pair对实际是两个entry。所以,此时ziplist中的entry数量已经达到了 1024 个

以上条件,每次都会顺序依次检查。另外,这种转换是不可逆的

Part 2: dict 数据结构的hash

这些 callback 前面也都见过,没什么特别的。但是有一点,这些都是 string。

Part 3: integer 与 float 类型数据在hash中的存储

1. integer: 在进入ziplist之前,interger 以 字符的形式,设置进ziplist,而ziplist针对每个进入ziplist中的string,都会进行stringtolong的尝试转换。然后按照对应的encoding方式进行存储。

2. 对于float,内部会将float转成文本,设置进入ziplist。为了保持float类型数的精度,hash内部存储float的数据结构可以很大。每次ldtostring的转换,都会有一个 5k 大小的栈缓存。此外,redis对浮点类型的数都进行了大量的额外的处理,只是为了保持其精度。所以,尽量不要往redis中尤其是 hash 类型中存储浮点类型数据。

PS:

此处发现一个与存储string value不一样的地方,前文已经提到ziplist to dict的转换问题。

前面的条件一,在设置string类型field-value,会检查field以及value的长度(保持在64以内)。这个转换检查,在hincrby* 命令处理中,没有做,此时 field的长度超过64,ziplist 也不会被convert成dict。应该是个bug。(版本:5.0.7)

hincrby* 命令只会进行以上所提到的第二点的检查。

PS: 

1. hash类型当采用ziplist时,都是找到 field-value pair,删除掉value所在的entry,然后在原先value的entry索引处,去insert对应的value.

2. 当hash类型底层采用dict存储数据时,每次 HDEL key field,就会触发另外一个操作,检查是否需要resize。条件便是前文所述的条件:利用率低于10%。主要数据存储的dict以及expires,在DEL命令执行时,是没有这个检查的。

3. 许多论坛帖子上所说的个数限制,通篇代码都没找到针对某个hash类型的内部数量的判断代码。所以,所说的2^32-1 个的限制,没找到。每个dict,有两张hashtable,每张hashtable中计数used的类型是unsigned long,64bit机器长度为8个字节,那应该是2^64-1才对。

适用场景

hash 非常适合存储原始实体对象类型。

1. 操作原子性可以保证并发安全

2. field可以独立设置,修改或者获取,无需整体序列化或者逆序列化等操作

3. 对于整体的设置,获取也提供了相应的API进行操作

不足之处

最大的不足,就是支持的数据类型 field 只支持 stringvalue只支持string以及integer(对于double也都是采用string转储的)

这样对于组合类型的数据对象,需要额外的处理:

方案1. 可以采用序列化的方式,对某个域整体获取,序列化或者逆序列化进行操作

方案2. 可以采用另外一个hash,用 new key 值作为原始 hash field value

 

方案1不足之处在于,需要局部序列化与逆序列化的操作

方案2不足之处在于,业务层面需要二次甚至多次访问Redis才能获取到“全貌”实体

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值