那问题来了“
hash算法是不能保证 所有的key 经过算法出来的值都一样,那就是会有哈希冲突的存在,就是 两个key放到了同一个桶 中,这可怎么办呢?
”
我们就用 链表 来解决这个问题,就是两个在一个桶中的元素,我们就用一个next指针把它们 连在一起,经过hash算出来之后找到一个键值对,对比看着 如果不是,根据next指针再找下一个比就行 。我们都知道链表是一种常用的数据结构,而C语言内部是 没有内置 这种数据结构的实现,所以我redis会自己构建了 链表 的实现 。
其中每个
链表节点
使用一个listNode结构表示:(下图的右部分):
//链表节点typedef struct listNode{struct listNode * prev;struct listNode * next;void * value;}
下图是有两部分,由list和listNode两个数据结构构成 。一部分是“ 统筹部分 ”是左边,一部分是“ 具体实施 “:右边;
文章插图
主体”统筹部分“:head指向具体 双向链表的头
tail指向具体 双向链表的尾
len双向链表的
长度
;
具体"实施方":可以看出每个链表节点都有指向 前置节点prev 和 后置节点next 的指针,组成一个双向链表 。每个链表结构,有表头表尾指针和链表长度等信息 。另外表头节点和前置和表尾节点的 后置都是NULL,所以是无环链表 。
在总结下:
特点:
- 双端 :链表节点带有prev和next指针,找到某个节点的前置节点和后置节点的 时间复杂度都是O(N)
- 无环 :表头节点的prev指针和表尾节点的next 都指向NULL,对立案表的访问时以 NULL为截止
- 表头与表尾 :因为链表带有head指针和tail指针,程序获取链表头结点和尾节点的时间复杂度为O(1)
- 长度计数器 :链表中存有记录链表 长度 的属性**len
- 多态 :链表节点使用void* 指针来保存节点值,并且可以通过list结构的dup 、free、match三个属性是节点值设置类型特定函数 。
typedef struct list {//表头节点listNode* head;//表尾节点listNode* tail;//链表长度unsigned long len;//节点值复制函数void *(*dup) (void *ptr);//节点值释放函数void (*free) (void *ptr);//节点值对比函数int (*match)(void *ptr, void *key);}
“那么当元素越来越多之后,一个哈希桶所 对应的链表 就会越来越长,我们知道链表上的遍历时间复杂度是O(n)的,那么会严重 影响性能,Redis这种追求快的数据库看来是绝对不能够 容忍 的,那么要怎么处理,就是rehash操作 。
”
rehash和渐进式rehash操作redis会在 内部再新建 一个长度为原始长度2倍的空哈希表,然后原哈希表上的元素 重新rehash 到新的哈希表中去,然后我们再使用新的哈希表即可 。
那么,这样还是有个问题要解决呀!
要知道redis中存储的数据可能是成百万上千万的,我们 重新rehash 一次未免太耗时了吧,因为redis中操作大部分是 单线程 的 。
“
这个过程可能会阻断其他操作很长时间,这是不能忍受的,那要怎么处理呢?
”
首先redis是采用了 渐进式rehash 的操作,就是会有一个变量,指向第一个哈希桶,然后redis每执行一个添加key,删除key的类似命令,就顺便 copy一个哈希桶中的数据 到新的哈希表中去,这样细水长流的操作,是不会影响什么性能,就会所有的数据都被重新hash到新的哈希表中 。
那么在这个过程中,当然再有写的操作,会直接把数据放到新的哈希表中,保证旧的肯定有 copy完 的时候,如果这段时间对数据库的操作比较少,也没有关系,redis 内部也有定时 任务,每隔一段时间也会copy一次 。
动态字符串SDSSDS的全称"simple dynamic string" 。redis中所有场景中出现的字符串,基本都是由SDS来实现的 。
所有 非数字的key。例如 set msg "hello world" 中的key msg.
字符串数据类型的值。例如 set msg "hello world"中的msg的值"hello wolrd"
最后是两者结合:
非字符串数据类型中的“字符串值”
。例如 RPUSH fruits "Apple""banana""cherry"中的"apple" "banana" "cherry"都是;
上面的例子,我们可以很直观地看到我们在平常使用redis的时候,创建的字符串到底是一个什么样子的数据类型 。除了用来保存字符串以外,SDS还被用作 缓冲区 (buffer)AOF模块中的 AOF缓冲区。
推荐阅读
- 李自成灭亡的真正原因,李自成失败的根本原因是什么
- 朱元璋杀李善长的真正原因是什么?,朱元璋为何杀李善长全家
- OceanBase开源,11张图带你了解分布式数据库的核心知识
- reflector 带你彻底搞懂MyBatis的底层实现之反射工具箱
- 真正降血压的茶,降血压喝什么茶最好
- 一篇文章带你搞懂Python中的类
- 软件测试知识点3大场景带你了解单元测试
- 秦始皇不立皇后的真正原因,秦始皇为什么终身不立后
- 历史上真正的刘彧,刘彧是不是昏君
- 乾隆身世之谜-到底谁是弘历生母-乾隆果真是汉女所生-?乾隆与其母的真正关系_1