Redis 字典结构细谈
Redis 字典底层基于哈希表实现。
一、哈希表结构
1、dictht:
typedef struct dictht {
dictEntry **table; //哈希表数组,存储具体的键值对元素,对象类型 dictEntry
unsigned long size; //哈希表容量
unsigned long sizemask; //哈希表大小掩码,计算索引使用
unsigned long used; //已使用容量
} dictht
2、示例数据:
二、哈希表节点
1、dictEntry:
typedef struct dictEntry {
void *key; //键值对 key
union{ //键值对 value 三种类型
void *val;
uint64_tu64;
int64_ts64;
} v;
struct dictEntry *next; //下一个节点指针
} dictEntry;
说明:next 为指向下一个节点的指针,是我们熟悉的链表节点结构,单向链表,用于处理键哈希冲突问题。
相同哈希值的键的键值对会以链表的形式存在同一位置。
2、示例数据:
三、Redis 字典
1、dict:
typedef struct dict{
dictType *type; //类型特定函数
void *privdata; //私有数据
dictht ht[2]; //哈希表数组,类型为dictht,ht[0]为实际存储数据使用,ht[1] 为rehash时使用
int rehashidx; //rehash进度标志,-1 代表当前不在 rehash
} dict
2、示例数据:
四、添加元素
向字典中添加元素主要涉及一下几步操作:
1、计算键值对键的哈希值
hash:dict->type->hashFunction(key)
使用dictType内部的哈希函数得到键哈希值
2、计算需要放入的位置索引
index:hash&dict->ht[0].sizemask
使用上一步计算得到的哈希值与哈希表的sizemask属性进行与操作得到需要放入的位置索引值
3、键冲突解决
没有完美的哈希函数,哈希冲突往往无法避免,当多个键被所引导同一个位置时,这种现象,我们称之为键冲突。
解决间冲突,Redis 采用链地址法,也即将冲突的键值对组成一条链条放到同一个哈希位置上。上面第二节我们介绍过 dictEntry的结构,其中包含一个指向另一个节点的指针next。
这里需要说明的一点是,冲突节点插入时,是插入到链表的头部,这样只需要执行操作一次操作即可,也即时间复杂度为O(1)。
如下图:(k2,v2)与(k1,v1)发生冲突,直接将(k2,v2)插入到链表头部:
五、rehash
rehash过程是在重新规划哈希表占用空间时发生的。
负载因子 load_factor:已保存节点数量(dict.ht[0].used)/ 哈希表容量(dict.ht[0].size)
负载因子用以表名当前哈希表的使用状态,它需要保持在一个合理的范围,以保障资源的最优利用。通常需要适时的对哈希表进行扩展或者收缩来对负载因子进行维护,而这个过程,我们称之为 rehash。
这里涉及到一个问题,就是什么时候需要进行伸缩维护?
1、扩展时机:
当前无bgsave及bgrewriteaop操作,load_factor >= 1
当前存在bgsave及bgrewriteaop操作,load_factor >= 5
Redis服务器通过fork子进程形式执行bgsave及bgrewriteaop操作,此时整个服务的资源耗费较大,为了避免可能发生的rehash带来额外的资源压力,此期间,服务器会调高触发执行扩展操作的负载因子界限。
2、收缩时机:
load_factor < 0.1
3、rehash 基本操作:
a) 为dict.ht[1]分配空间:
空间大小计算如下:
扩展:最小n满足2n >= dict.ht[0].used * 2
收缩:最小n满足2n >= dict.ht[0].used
如下图:ht[0].used = 3,假定无bg相关任务,则h[1]大小需要计算:2n >= 3 * 2 = 6
n = 3,ht[1].size = 23 = 8
b) rehash
对于dict.ht[0] 中的元素,依据dict.ht[1]特性(sizemask)重新计算索引值,并放置到dict.ht[1]中。
c) 当所有元素迁移完毕,释放dict.ht[0],并将dict.ht[1]设置为dict.ht[0],重新在dict.ht[1]上创建空的哈希表。
六、渐进式rehash
所谓渐进式,是针对大数据量字典数据。直接一次性的执行rehash会导致服务资源的集中占用,影响正常的服务响应。因此需要进行分而治之。
这里会用到上面我们介绍的dict字典结构中的 rehashidx属性,用以标识当前rehash进度。
首先将rehashidx置0,标示rehash开始,每次rehash一个元素,rehashidx值增加1,当最终所有元素rehash完成,将rehashidx置-1。
这里需要说明下rehash中对正常的服务请求的处理:
1、删除、查找、更新:
会涉及到两个哈希表(ht[0]、ht[1])操作,如查找元素,首先尝试在ht[0]上查找,找不到,则继续在h[1]上查找。
2、添加
添加元素只会在h[1]上操作,h[0]上只减不增。
Redis 字典结构细谈的更多相关文章
- 《闲扯Redis七》Redis字典结构的底层实现
一.前言 上节<闲扯Redis六>Redis五种数据类型之Hash型 中说到 Hash(哈希对象)的底层实现有: 1.ziplist 编码的哈希对象使用压缩列表作为底层实现 2.hasht ...
- Redis核心原理与实践--散列类型与字典结构实现原理
Redis散列类型可以存储一组无序的键值对,它特别适用于存储一个对象数据. > HSET fruit name apple price 7.6 origin china 3 > HGET ...
- redis中的字典结构是怎样的?
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. 基础概念 redis支持的5种数据类型中,有hash类型,hash类型的 ...
- 【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构
redis 是使用 C 语言编写的,但是 C 语言是没有字典这个数据结构的,因此 C 语言自己使用结构体来自定义一个字典结构 typedef struct redisDb src\server.h 中 ...
- REDIS 字典数据结构
对于REDIS来讲 其实就是一个字典结构,key ---->value 就是一个典型的字典结构 [当然 对于vaule来讲的话,有不同的内存组织结构 这是后话] 试想一个这样的存储场景: ...
- redis 字典
redis 字典 前言 借鉴了 黄健宏 的 <<Redis 设计与实现>> 一书, 对 redis 源码进行学习 欢迎大家给予意见, 互相沟通学习 概述 字典是一种用于存储键值 ...
- Redis 字典的实现
[Redis 字典的实现] 注意 dict 类型使用了两个指针,分别指向两个哈希表. 其中, 0 号哈希表(ht[0])是字典主要使用的哈希表, 而 1 号哈希表(ht[1])则只有在程序对 0 号哈 ...
- [算法]从Trie树(字典树)谈到后缀树
我是好文章的搬运工,原文来自博客园,博主July_,地址:http://www.cnblogs.com/v-July-v/archive/2011/10/22/2316412.html 从Trie树( ...
- 阿里面试官:HashMap 熟悉吧?好的,那就来聊聊 Redis 字典吧!
最近,小黑哥的一个朋友出去面试,回来跟小黑哥抱怨,面试官不按套路出牌,直接打乱了他的节奏. 事情是这样的,前面面试问了几个 Java 的相关问题,我朋友回答还不错,接下来面试官就问了一句:看来 Jav ...
随机推荐
- Httprunner框架学习
前言 HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试. 官方文档:https://docs.httprunner. ...
- Java并发编程之闭锁与栅栏
一.前言 闭锁与栅栏是在多线程编程中的概念,因为在多线程中,我们不能控制线程的执行状态,所以给线程加锁,让其按照我们的想法有秩序的执行. 闭锁 CountDownLatch,实例化时需要传入一个int ...
- do...while 循环
语法 C 语言中 do...while 循环的语法: do { statement(s); }while( condition ); 请注意,条件表达式出现在循环的尾部,所以循环中的 statemen ...
- Java沙箱安全机制介绍【转载】
沙箱安全机制的应用层面:360沙箱.win10沙箱.包括VMware Workstation.Oracle VM VirtualBox都可以充当沙箱去使用,沙箱中的操作与本机无关,进而保证本机的安全性 ...
- 我的Python自学之路-001 列表的知识
#_date_:2020/9/11 '''列表和字典是python中用的最多的数据类型 假如要存储一个班级的人名,需要怎么做?有这么几种方法:1.定义很多个变量: name0 = 'wucaho' n ...
- 【JVM系列1】深入分析Java虚拟机堆和栈及OutOfMemory异常产生原因
前言 JVM系列文章如无特殊说明,一些特性均是基于Hot Spot虚拟机和JDK1.8版本讲述. 下面这张图我想对于每个学习Java的人来说再熟悉不过了,这就是整个JDK的关系图: 从上图我们可以看到 ...
- 立下flag!
从今日(2020年6月29日)开始,直到两个月的暑假结束2020年8月31日,每天vp一场div3,至少要ac4道题目.
- 想要搭建个论坛?Guide哥调研了100来个 Java 开源论坛系统,发现这 5 个最好用!
大家好!我是 Guide 哥,Java 后端开发.一个会一点前端,喜欢烹饪的自由少年. 最近有点小忙.但是,由于前几天答应了一位读者自己会推荐一些开源的论坛系统,所以,昨晚就简单地熬了个夜,对比了很多 ...
- 刷题[CISCN2019 华北赛区 Day2 Web1]Hack World
解题思路 打开发现是很简单的页面,告诉了表名和列名,只需知道字段即可 尝试一下,输入1,2都有内容,后面无内容.输入1'让他报错,发现返回bool(false) 大概思路就是布尔型注入了,通过不断返回 ...
- Typecho反序列化漏洞
Typecho Typecho是一款快速建博客的程序,外观简洁,应用广泛.这次的漏洞通过install.php安装程序页面的反序列化函数,造成了命令执行,Typecho 1.1(15.5.12)之前的 ...