• Redis之字典


    概念

      字典,又称为符号表、关联数组或映射(map),是一种用于保存键值对(key-value pair)的抽象数据结构。字典中每个键都是独一无二的,程序可以根据键来更新值,或者删除整个键值对。

    用途

    1. Redis的数据库就是使用字典来作为底层实现
    2. 字典还是哈希键的底层实现之一。当一个哈希键包含的键值对比较多,又或者键值对中的元素都是比较长的字符串时,Redis就会使用字典作为哈希键的底层实现。

    字典的实现

      Redis的字典使用哈希表作为底层实现,一个哈希表里面可以有多个哈希表节点,而每个哈希表节点就保存了字典中的一个键值对。

     (Redis中dict是hash键的底层实现之一,而dict的底层又采用了hash表。hash表dictht包含了一个dictEntry数组,size记录了hash表的大小,sizemask始终等于size-1,还有一个used记录了已有节点的数量

      hash表节点dictEntry是一个键值对对象,另外还有一个next指针,指向下一个dictEntry,通过指针连接在一起,可以解决键冲突的问题

      )

    哈希表

    1. table : 一个数组,数组中每个元素都是一个指向dict.h/dictEntry(哈希表节点)结构的指针,而每个dictEntry都保存了一个键值对
    2. size:记录了hash表的大小,也就是table数组的大小
    3. used:记录了hash表已有哈希表节点(键值对)的数量
    4. sizemask:总是等于size-1 

    哈希表节点

    1. key:保存键
    2. v :保存键值对中的值,可以是一个指针,或者一个uint64_t整数,又或者是一个int64_t整数
    3. next :只想两一个哈希表节点的指针,多个指针将多个哈希值相同的键值对连接在一起,解决了键冲突的问题

     字典

    1. type : 是一个指向dictType的指针,每一个dictType结构保存了一簇用于操作特定类型键值对的函数,Redis会为用途不同的字典设置不同的类型特定函数
    2. privdata : 保存了需要传给那些特定函数的可选参数
    3. ht[2] : 包含两个项(hash表)的数组,一般只用ht[0],ht[1]只有在rehash时使用
    4. trehashidx:记录rehash目前的进步,如果没在进行rehash,那么值为-1

    解决键冲突

      Redis根据键值对的键计算出哈希值喝索引值,然后根据索引值,将包含新键值对的哈希表节点放到哈希表数组的指定索引上面。

       当两个或者以上数量的键被分配到哈希表数组的同一索引上面时,我们称这些键发生了冲突。

       Redis的哈希表采用链地址法解决键冲突。每个哈希表节点都有一个next指针,多个哈希表节点用next指针连接在一起,多个节点用这个单向链表连接起来,这就解决了链冲突。

    Rehash

    1. 扩展操作:ht[1]的大小为第一个大于等于ht[0].used*2的2n(2的n次方)
    2. 收缩操作:ht[1]的大小为第一个大于等于ht[0].used的2n

    当满足以下任意一个条件时,程序会自动进行扩展操作:

    • 服务器没有正在执行BGSAVE命令或者BGREWRITEAOF命令,并且哈希表负载因子大于等于1
    • 服务器正在执行BGSAVE或者BGREWRITEAOF命令,并且哈希表负载因子大于等于5
    • 负载因子计算公式:load_factor = ht[0].used / ht[0].size

    rehash步骤:

    • 为字典ht[1]分配空间
    • 将保存在ht[0]中的所有键值对rehash到ht[1]上
    • ht[0]所有键值对迁移完后,释放ht[0],将ht[1]设置为htp[0],并在ht[1]创建一个空白哈希表,为下一次rehash做准备

    渐进式rehash

      为避免rehash对服务器性能的影响,服务器不是一次性将ht[0]力所有的键值对全部rehash到ht[1]中,而是分多次,渐进式的rehash到ht[1]中

    详细步骤:

    1. 在ht[1]分配空间,让字典同时持有ht[0]和ht[1]两个哈希表
    2. 维持一个索引计数器变量rehashidx,设置为0,表示rehash开始
    3. 在rehash期间,每次对字典执行添加,删除,查找或者更新操作时,程序除了执行指定的操作以外,还会顺带及那个ht[0]哈希表在rehashidx索引上的所有键值对rehash到ht[1]上,当rehash完成时,rehashidx属性值增一
    4. 随着字典操作不断执行,最终在某个时间点,ht[0]的所有键值对都被rehash到ht[1]上,这时将rehashidx设置为-1,表示rehash完成

    在rehash过程中,字典同时拥有ht[0]和ht[1]两个哈希表,期间字典的删除,查找,更新等操作会在两个哈希表进行。例如查找,先在ht[0]查找,如果没有就在ht[1]查找。另外在rehash期间,新添加的字典的键值对一律会保存到ht[1]中,ht[0]则不再进行任何添加操作,这保证ht[0]包含的数量只减不增,最终变为空表。

  • 相关阅读:
    【转载】八大排序算法
    【转载】算法的时间复杂度和空间复杂度的计算
    【转载】SpringMVC前台给后台传值的方式
    Session方法
    配置《算法 第四版》的Eclipse开发环境
    Learning Scrapy笔记(三)- Scrapy基础
    Learning Scrapy笔记(七)- Scrapy根据Excel文件运行多个爬虫
    Learning Scrapy笔记(六)- Scrapy处理JSON API和AJAX页面
    Scrapy Learning笔记(四)- Scrapy双向爬取
    Learning Scrapy笔记(五)- Scrapy登录网站
  • 原文地址:https://www.cnblogs.com/TripL/p/13298460.html
Copyright © 2020-2023  润新知