Redis的设计与实现-读书笔记(一)

文章目录

  • SDS
    • SDS的定义
    • SDS与C风格字符串的区别
  • 链表
    • Redis中链表的结构
  • 字典
    • 字典的实现
    • 解决键冲突
    • 处理负载因子
  • 跳表

SDS

SDS的定义

在Redis中使用SDS(简单动态字符串)来代替c风格字符串

struct SDS{
	int len,free;
	char buf[];
}

SDS与C风格字符串的区别

  • O(1)获取SDS长度
  • 通过分析free来杜绝缓冲区溢出
  • 通过空间预分配(大于1M分配1M,小于1M分配2倍)和惰性释放(提供了内存释放API)减少内存分配次数
  • 二进制安全(因为使用len而不是’\0’来判断结束)
  • SDS使用’\0’来结尾,所以可以复用部分C函数

链表

列表,慢查询,发布订阅,监视器等功能中都用到了链表

Redis中链表的结构

typedef struct list{
	listNode *head,*tail;//头,尾
	unsigned long len;//长度
	void *(*dup)(void *ptr);//复制函数
	void (*free)(void *ptr);//释放函数
	int (*match)(void *ptr,void *key);//匹配判断函数
}list;

listNode 的底层是双向无环链表

字典

Redis中数据库,哈希表等功能的底层都用到了字典

字典的实现

typedef struct dictht{
	dictEntry **table;//值数组
	unsigned long size; // 哈希表大小
	unsigned long sizemask;//掩码
	unsigned long used;//已使用数量
}
typedef struct dictEntry{
	void *key;//键
	union{//值
		void *val;
		uint64_t u64;
		int64_t s64;
	}v;
	struct dictEntry *next;//下个哈希表节点
}dictEntry;
typedef struct dict{
	dictType* type;
	void *privatedata;
	dictht ht[2];//维护两个,为了完成负载因子均衡
	int trehashidx;//不在rehash时,值为-1
}

在Redis中会根据不同的键类型,选择不同的处理函数(type->hashFunction() , 如计算,处理,销毁函数),Redis使用MH2算法.

解决键冲突

使用链地址法,在链的头部插入新节点,保证插入的O1复杂度

处理负载因子

负载因子 = 保存节点数量 / size
在进行bgsave,bgrewrite时 触发rehash的负载因子值为5 , 不进行时为 1 (因为要避免写时复制时多余的内存写入)

利用ht[1]来完成扩展(第一个大于used*2的2的幂)或者收缩(第一个大于used的2的幂) 空间大小
在大小改变后,将ht[0]中的元素rehash到ht[1]中,完成后交换两者地址,完成rehash

渐进式rehash:每次访问ht[0]时rehash一个rehashidx上的数据,当rehashidx等于达到上限时说明rehash完毕,将rehashidx置为-1(通过渐进rehash避免服务长时间停止响应)

rehash 读操作 会先在ht[0],后在ht[1]上读 , 写操作全部写在ht[1]

跳表

跳跃表支持平均logN,最坏o(N)的不稳定查找复杂度,可以通过顺序性批量操作节点,是有序列表的底层实现之一,还是集群内部的数据结构.

typedef struct zskiplistNode{
	struct zskiplistNode *backward; // 后退指针
	double score;//分数
	robj *obj;//实际对象
	struct zskiplistLevel{ //层
		struct zskiplistLevel *forward; //每层上的前进指针
		unsigned int span; // 跨度
	}level[];//层的大小是1~32的随机数
}zskiplistNode;

你可能感兴趣的:(redis)