热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

Redisbook学习笔记(1)字典(3)

渐进式rehash在上一节,我们了解了字典的rehash过程,需要特别指出的是,rehash程序并不是在激活之后就马上执行直到完成的,而是分多次、渐进式地完成的。假设这

渐进式rehash在上一节,我们了解了字典的rehash过程,需要特别指出的是,rehash程序并不是在激活之后就马上执行直到完成的,而是分多次、渐进式地完成的。假设这

渐进式rehash

在上一节,我们了解了字典的rehash 过程,需要特别指出的是,rehash 程序并不是在激活之

后就马上执行直到完成的,而是分多次、渐进式地完成的。

假设这样一个场景:在一个有很多键值对的字典里,某个用户在添加新键值对时触发了rehash

过程,如果这个rehash 过程必须将所有键值对迁移完毕之后才将结果返回给用户,这样的处理

方式将是非常不友好的。

另一方面,要求服务器必须阻塞直到rehash 完成,这对于Redis 服务器本身也是不能接受的。

为了解决这个问题,Redis 使用了渐进式(incremental)的rehash 方式:通过将rehash 分散

到多个步骤中进行,从而避免了集中式的计算。

渐进式rehash 主要由_dictRehashStep 和dictRehashMilliseconds 两个函数进行:
. _dictRehashStep 用于对数据库字典、以及哈希键的字典进行被动rehash ;
. dictRehashMilliseconds 则由Redis 服务器常规任务程序(server cron job)执行,用
于对数据库字典进行主动rehash ;
_dictRehashStep
每次执行_dictRehashStep ,ht[0]->table 哈希表第一个不为空的索引上的所有节点就会全
部迁移到ht[1]->table 。

在rehash 开始进行之后(d->rehashidx 不为-1),每次执行一次添加、查找、删除操作,
_dictRehashStep 都会被执行一次:

wKiom1Lfx8-xIvSUAAFG-ophSV4572.jpg

因为字典会保持哈希表大小和节点数的比率在一个很小的范围内,所以每个索引上的节点数量
不会很多(从目前版本的rehash 条件来看,平均只有一个,最多通常也不会超过五个),所以
在执行操作的同时,对单个索引上的节点进行迁移,几乎不会对响应时间造成影响。
dictRehashMilliseconds
dictRehashMilliseconds 可以在指定的毫秒数内,对字典进行rehash 。
当Redis 的服务器常规任务执行时,dictRehashMilliseconds 会被执行,在规定的时间内,
尽可能地对数据库字典中那些需要rehash 的字典进行rehash ,从而加速数据库字典的rehash
进程(progress)。
其他措施
在哈希表进行rehash 时,字典还会采取一些特别的措施,确保rehash 顺利、正确地进行:
因为在rehash 时,字典会同时使用两个哈希表,所以在这期间的所有查找、删除等操作,
除了在ht[0] 上进行,还需要在ht[1] 上进行。
在执行添加操作时,新的节点会直接添加到ht[1] 而不是ht[0] ,,这样保证ht[0] 的节
点数量在整个rehash 过程中都只减不增。

字典的收缩
上面关于rehash 的章节描述了通过rehash 对字典进行扩展(expand)的情况,如果哈希表的
可用节点数比已用节点数大很多的话,那么也可以通过对哈希表进行rehash 来收缩(shrink)
字典。
收缩rehash 和上面展示的扩展rehash 的操作几乎一样,它执行以下步骤:
1. 创建一个比ht[0]->table 小的ht[1]->table ;
2. 将ht[0]->table 中的所有键值对迁移到ht[1]->table ;
3. 将原有ht[0] 的数据清空,并将ht[1] 替换为新的ht[0] ;
扩展rehash 和收缩rehash 执行完全相同的过程,一个rehash 是扩展还是收缩字典,关键在于
新分配的ht[1]->table 的大小:
. 如果rehash 是扩展操作,那么ht[1]->table 比ht[0]->table 要大;
. 如果rehash 是收缩操作,那么ht[1]->table 比ht[0]->table 要小;
字典的收缩规则由redis.c/htNeedsResize 函数定义:

/* * 检查字典的使用率是否低于系统允许的最小比率 ** 是的话返回1 ,否则返回0 。 */ int htNeedsResize(dict *dict) { long long size, used; // 哈希表已用节点数量 size = dictSlots(dict); // 哈希表大小 used = dictSize(dict); // 当哈希表的大小大于DICT_HT_INITIAL_SIZE // 并且字典的填充率低于REDIS_HT_MINFILL 时 // 返回1 return (size && used && size > DICT_HT_INITIAL_SIZE && (used*100/size 在默认情况下,REDIS_HT_MINFILL 的值为10 ,也即是说,当字典的填充率低于10% 时,程
序就可以对这个字典进行收缩操作了。
字典收缩和字典扩展的一个区别是:
. 字典的扩展操作是自动触发的(不管是自动扩展还是强制扩展);
. 而字典的收缩操作则是由程序手动执行。
因此,使用字典的程序可以决定何时对字典进行收缩:
. 当字典用于实现哈希键的时候,每次从字典中删除一个键值对,程序就会执行一次
htNeedsResize 函数,如果字典达到了收缩的标准,程序将立即对字典进行收缩;
. 当字典用于实现数据库键空间(key space) 的时候, 收缩的时机由
redis.c/tryResizeHashTables 函数决定.

字典其他操作
除了添加操作和伸展/收缩操作之外,字典还定义了其他一些操作,比如常见的查找、删除和更
新。
因为链地址法哈希表实现的相关信息可以从任何一本数据结构或算法书上找到,这里不再对字
典的其他操作进行介绍,不过前面对创建字典、添加键值对、收缩和扩展rehash 的讨论已经涵
盖了字典模块的核心内容。

字典的迭代
字典带有自己的迭代器实现——对字典进行迭代实际上就是对字典所使用的哈希表进行迭代:
. 迭代器首先迭代字典的第一个哈希表,然后,如果rehash 正在进行的话,就继续对第二
个哈希表进行迭代。
. 当迭代哈希表时,找到第一个不为空的索引,然后迭代这个索引上的所有节点。
. 当这个索引迭代完了,继续查找下一个不为空的索引,如此循环,一直到整个哈希表都迭
代完为止。
整个迭代过程可以用伪代码表示如下:

def iter_dict(dict): // 迭代0 号哈希表 iter_table(ht[0]->table) // 如果正在执行rehash ,那么也迭代1 号哈希表 if dict.is_rehashing(): iter_table(ht[1]->table) def iter_table(table): // 遍历哈希表上的所有索引 for index in table: // 跳过空索引 if table[index].empty(): continue // 遍历索引上的所有节点 for node in table[index]: // 处理节点 do_something_with(node)
推荐阅读
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Redis中RDB文件和AOF文件的保存和还原机制。RDB文件用于保存和还原Redis服务器所有数据库中的键值对数据,SAVE命令和BGSAVE命令分别用于阻塞服务器和由子进程执行保存操作。同时执行SAVE命令和BGSAVE命令,以及同时执行两个BGSAVE命令都会产生竞争条件。服务器会保存所有用save选项设置的保存条件,当满足任意一个保存条件时,服务器会自动执行BGSAVE命令。此外,还介绍了RDB文件和AOF文件在操作方面的冲突以及同时执行大量磁盘写入操作的不良影响。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 面试经验分享:华为面试四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试
    最近有朋友去华为面试,面试经历包括四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试。80%的人都在第一轮电话面试中失败,因为缺乏基础知识。面试问题涉及 ... [详细]
  • __call是找不到方法的时候会执行可以代替下面的saddsrem方法publicfunction__call($name,$arguments){if(count($argum ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
author-avatar
果粒仙子妹妹
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有