redis渐进式rehash

引言

简单复习一下,redis有哪些数据结构和对象。

数据结构

  1. 连续内存类

    1. SDS 简单动态字符串
    2. 整数集合intset
    3. 压缩链表ziplist
  2. 随机内存类

    1. list和listnode
    2. zskiplist和zskiplistnode
  3. 连续+随机:dict、dictht和dictEntry

对象

总共有5种:

  1. string
  2. list
  3. hash
  4. set
  5. zset

其中,hash对象的内部实现是redis的字典,也就是dict结构,dict结构有两个字段和rehash有关:

  1. 两个hash表(hash表是dictht结构)
  2. rehashidx,记录rehash的进度

渐进式rehash

需要渐进式rehash的原因:

  1. 随着client对hash对象的增删数据操作,hash对象里的元素会相应的增加或减少,导致内存利用率变低或增加hash碰撞几率,因此需要对其底层的哈希表进行扩缩容。扩缩容的标准是底层哈希表的负载因子;
  2. 扩缩容,需要相应地重新计算key在新的哈希表中的位置,这是一个消耗cpu算力的操作;

这就是渐进式rehash出现的原因,rehash的需求加上一次性rehash的性能问题。

渐进式rehash触发的条件

分为扩容和缩容:

  1. 扩容,分为有没有正在执行bgsave(生成RDB文件)或bgrewriteaof命令(重写AOF)

    1. 正在执行,判断负载因子>=5
    2. 没有在执行,判断负载因子>=1

    已知生成RDB文件或重写AOF也是比较消耗cpu算力的操作,因此对这两个数值的不同,就可以理解了。

  2. 缩容:简单粗暴,负载因子<=0.1

附上负载因子计算公式:used / size (哈希表已使用的键数量/容量)

渐进式rehash的过程

参考:https://tech.meituan.com/2018...

在没有rehash时,dict结构里面的两个dichht结构,有一个的table指向的是空指针,即,这个样纸:
redis渐进式rehash_第1张图片

基于此状态描述渐进式rehash(扩容情况下)的过程:

  1. 为ht[1]分配一块新的内存,内存空间大小按照DICT_HT_INITIAL_SIZE * 2的n次方 >= h[0].used,这里>=的意思是第一个大于h[0].used的值;(在rehash过程中会一直维持这个内存消耗);
  2. 在rehash过程中,所有对h[0]的删改查操作,都会触发h[1]同样的操作,同时进行一次rehash,把h[0]的中h[0].table[rehashidx]位置的数据挪到h[1],然后给rehashidx+1;新增操作则会直接放到h[1]中;
  3. 每次rehash函数最后会判断h[0].used==0,if true,结束渐进式rehash过程。

参考:https://blog.csdn.net/weixin_...

你可能感兴趣的:(redis)