Hash 结构
回顾Java中的hashMap https://www.yuque.com/wangchao-volk4/fdw9ek/hy2lrc
redis 中的 Hash和 Java的 HashMap 更加相似,都是数组+链表的结构.当发生 hash 碰撞时将会把元素追加到链表上.值得注意的是在 Redis 的 Hash 中 value 只能是字符串。并且 Redis 中的 hash 并没有使用 红黑树,只有数组加链表,这与jdk1.8之前的hashMap类似。
在 Java 中 HashMap 扩容是个很耗时的操作,需要去申请新的数组,为了追求高性能,Redis 采用了 渐进式 rehash 策略.这也是 hash 中最重要的部分。
rehash
在扩容的时候 rehash 策略会保留新旧两个 hashtable 结构,查询时也会同时查询两个 hashtable,Redis会将旧 hashtable 中的内容一点一点的迁移到新的 hashtable 中,当迁移完成时,就会用新的 hashtable 取代之前的。当 hashtable 移除了最后一个元素之后,这个数据结构将会被删除。
数据搬迁的操作放在 hash 的后续指令中,也就是来自客户端对 hash 的指令操,.一旦客户端后续没有指令操作这个 hash。Redis就会使用定时任务对数据主动搬迁。
正常情况下,当 hashtable 中元素的个数等于数组的长度时,就会开始扩容,扩容的新数组是原数组大小的 2 倍。如果 Redis 正在做 bgsave(持久化) 时,可能不会去扩容,因为要减少内存页的过多分离(Copy On Write)。但是如果 hashtable 已经非常满了,元素的个数达到了数组长度的 5 倍时,Redis 会强制扩容。
当 hashtable 中元素逐渐变少时,Redis 会进行缩容来减少空间占用,并且缩容不会受 bgsave 的影响,缩容条件是元素个数少于数组长度的 10%。