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

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

渐进式rehash

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

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

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

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

方式将是非常不友好的。

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

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

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

Get笔记 Get笔记

Get笔记,一款AI驱动的知识管理产品

Get笔记 125 查看详情 Get笔记

渐进式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 时// 返回1return (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)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/539158.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
当耳机遇上AI竟如此神奇,录音降噪会议耳机iFLYBUDS Nano+评测
上一篇 2025年11月9日 14:23:39
《鸣潮》今汐Cost3声骸获取线路详细推荐
下一篇 2025年11月9日 14:23:41

相关推荐

  • 如何用Golang构建无状态微服务 分享Session管理最佳实践

    如何用Golang构建无状态微服务 分享Session管理最佳实践如何用Golang构建无状态微服务 分享Session管理最佳实践如何用Golang构建无状态微服务 分享Session管理最佳实践如何用Golang构建无状态微服务 分享Session管理最佳实践

    构建无状态微服务时,session管理可通过jwt、redis和统一认证中心实现。①使用jwt作为token,客户端存储,服务端无状态;②结合redis记录session元数据,支持主动失效;③设立统一认证中心,中间件校验token;④确保https传输安全并设计token刷新机制。 用 Golan…

    2026年5月10日 用户投稿
    000
  • 怎样用Golang实现一个简单的键值存储 基于文件持久化方案

    怎样用Golang实现一个简单的键值存储 基于文件持久化方案怎样用Golang实现一个简单的键值存储 基于文件持久化方案怎样用Golang实现一个简单的键值存储 基于文件持久化方案怎样用Golang实现一个简单的键值存储 基于文件持久化方案

    要实现一个简单的键值存储系统,需结合golang与文件持久化方案。1. 使用map[string]string作为内存数据结构,选择json或gob进行序列化;2. 围绕map实现crud操作,写入后立即或定时刷新到磁盘,并在启动时加载数据;3. 文件策略可选每次写入刷盘、定时异步刷盘或日志记录变更…

    2026年5月10日 用户投稿
    000
  • python中怎么删除字典中的键值对_Python删除字典元素的方法

    删除字典键值对有四种方法:del语句删除指定键,pop()删除键并返回值,popitem()随机删除键值对,clear()清空字典。 在 Python 中,删除字典中的键值对主要有几种方式:使用 del 语句直接删除指定键,利用 pop() 方法删除指定键并获取其对应的值,或者通过 popitem(…

    2026年5月10日
    000
  • C#的System.IO.Pipelines是什么?如何实现高性能的流处理?

    System.IO.Pipelines通过PipeReader和PipeWriter减少内存分配与拷贝,高效处理流数据,适用于高吞吐、低延迟场景如网络通信和协议解析。 System.IO.Pipelines 是 C# 中用于高效处理流数据的一个库,特别适合高吞吐、低延迟的场景,比如网络通信、文件解析…

    2026年5月10日
    100
  • WebSocket消息队列处理性能优化

    优化WebSocket性能需解耦通信与业务逻辑,通过消息队列异步处理、二进制序列化、数据压缩、批量发送及动态心跳机制,提升吞吐量并降低延迟。 处理WebSocket消息时,性能瓶颈常出现在消息的接收、处理和分发环节。优化核心在于解耦通信与业务逻辑,并高效管理消息流。 引入消息队列进行异步解耦 直接在…

    2026年5月10日
    000
  • Laravel Session::put 正确用法详解与常见误区规避

    本文详细探讨了 laravel 中 `session::put` 方法的正确用法,特别指出在仅提供键名而未指定值时可能导致会话数据未被正确设置的问题。通过示例代码,阐述了如何为会话数据赋予明确的值,并演示了如何正确地检查和获取会话数据,以确保会话管理功能按预期工作,有效避免常见的会话操作错误。 La…

    2026年5月10日
    000
  • PHP大型配置管理:结构化数据与外部文件实践

    本文旨在探讨在php项目中高效管理大量配置项的最佳实践。我们将摒弃直接创建数百个独立php变量或在配置文件中混合代码的低效方式,转而介绍如何利用php数组以及ini、json、yaml等外部结构化数据格式来组织和加载配置,并结合业务逻辑进行处理,从而提升代码的可维护性、可扩展性和专业性。 在PHP应…

    2026年5月10日
    100
  • php调用视频处理功能_php调用FFmpeg处理视频文件

    答案:PHP通过exec()等函数调用系统FFmpeg命令实现视频处理。需先安装FFmpeg,再使用exec()执行转码、截图、裁剪等操作,如截图示例:ffmpeg -i input.mp4 -ss 00:00:10 -vframes 1 cover.jpg;常见操作包括格式转换、分辨率调整、音频提…

    2026年5月10日
    000
  • 深度剖析 Go 语言在分布式缓存开发中的常见技术问题

    在使用 go 语言开发分布式缓存时,我们会遇到并发访问、数据一致性和性能优化等技术问题。1) 并发访问可通过 sync.mutex、sync.rwmutex 或 sync.map 解决,但高并发下可能需使用分片锁优化。2) 数据一致性可通过先更新数据库再更新缓存的方式实现,但在高并发下需引入分布式锁…

    2026年5月10日
    000
  • php调用数据同步方案_php调用多数据库数据同步

    首先明确同步需求与模式,如单向、双向、定时或实时同步;接着使用PHP通过PDO连接多数据库,基于时间戳或增量ID同步变更数据,并记录同步状态;为提高可靠性,可引入消息队列、binlog解析、中间同步层及加锁机制;最后注意网络超时、分页处理、错误重试、日志记录与测试验证,确保数据一致性与系统稳定性。 …

    2026年5月10日
    000
  • HTML表单如何实现白名单功能?怎样只允许授权用户?

    要实现%ignore_a_1%的白名单功能并确保只有授权用户操作,核心答案是必须依赖后端服务器进行严格的身份认证、会话管理、授权检查和数据验证,前端仅能提供用户体验层面的初步提示而不能保障安全;具体而言,首先通过用户身份认证(如用户名/密码或oauth)确认用户身份,服务器创建会话并返回标识符,后续…

    2026年5月10日
    800
  • 如何使用Go语言编写高性能键值对存储器?

    Go语言高性能键值存储方案探讨 本文探讨如何使用Go语言构建一个高性能的键值对内存存储,类似于Redis。许多开发者首先想到的是使用map,但Go的map并非线程安全。虽然sync.Map解决了这个问题,但其性能是否最佳仍存在争议。因此,我们需权衡sync.Map、第三方concurrentMap以…

    2026年5月10日
    100
  • PHP代码怎么压缩文件_ PHP文件压缩库调用与解压方法

    答案:PHP处理文件压缩解压主要使用ZipArchive类,可创建或提取ZIP文件,结合PharData和zlib扩展支持TAR、GZ等格式;需注意内存、执行时间、权限及文件名编码问题。 PHP代码要压缩或解压文件,核心是利用PHP内置的 ZipArchive 类。这个类提供了相当全面的功能,无论是…

    2026年5月10日
    000
  • 优化字符串查找:内存映射 vs. 数据库查询

    在Go服务器应用开发中,经常会遇到需要对接收到的字符串进行验证的场景,例如验证字符串是否存在于数据库中。针对高并发的HTTP请求,如何高效地进行字符串查找是一个关键问题。通常有两种策略:一是每次请求都执行SQL查询;二是将所有字符串预先加载到内存中的Map,然后通过Map进行快速查找。选择哪种策略取…

    2026年5月10日
    000
  • Golang微服务健康检查与自动恢复技巧

    Golang微服务通过/healthz端点实现健康检查,返回200或500状态码;2. 检查内容包括服务状态、依赖连接和资源使用;3. 与Consul或Kubernetes联动,利用liveness/readiness探针触发恢复;4. 内置自愈逻辑如协程重启、连接重连,配合退避策略;5. 健康检查…

    2026年5月10日
    000
  • PHP源码缓存机制实现_PHP源码缓存机制实现教程

    Opcode缓存是PHP性能优化的核心机制,通过将PHP脚本编译后的Opcode存储在共享内存中,避免每次请求重复解析和编译,显著降低CPU和I/O开销。首次请求时Zend引擎将PHP代码编译为Opcode并由OPcache等扩展存入共享内存;后续请求直接从内存加载Opcode执行,跳过文件读取与编…

    2026年5月10日
    100
  • Golang缓存机制提升访问效率实践

    使用sync.Map实现内存缓存,结合TTL过期与LRU淘汰策略,可有效提升高并发下Golang服务性能,减少数据库压力。 在高并发服务场景中,频繁访问数据库或远程接口会显著影响响应速度和系统负载。Golang 作为高性能语言,天然适合构建高效缓存机制来减少重复计算和外部依赖调用。通过合理使用内存缓…

    2026年5月10日
    000
  • 如何在Golang中实现购物车功能

    答案:通过定义用户、商品和购物项结构体,使用map管理购物车条目,实现添加、删除、计算总价功能,并结合HTTP接口与读写锁支持并发操作,适合扩展优惠券与库存校验。 在Golang中实现购物车功能,关键在于管理用户、商品和购物项之间的关系。通常使用结构体来表示数据模型,结合内存存储或数据库完成增删改查…

    2026年5月10日
    100
  • Golang性能优化的基本原则是什么 解析高效Go代码的核心准则

    go程序中常见的内存优化策略包括预分配切片容量、使用strings.builder或bytes.buffer进行字符串拼接、利用sync.pool复用对象以减少gc压力、避免大对象的值传递而改用指针传递、复用缓冲区以减少临时对象分配,以及警惕切片或字符串切片操作导致的底层数组隐式引用内存泄漏,这些策…

    2026年5月10日
    000
  • Laravel 会话机制详解:如何识别用户会话

    本文旨在深入解析 Laravel 框架中的会话管理机制,揭示 Laravel 如何利用 cookie 在服务器端存储会话数据,并准确地识别和恢复每个用户的会话。通过本文,你将了解 Laravel 会话的工作原理,以及如何利用它来构建安全可靠的 Web 应用程序。 Laravel 的会话管理系统建立在…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信