先来介绍一下redis,redis是一款内存高速缓存数据库,非关系型数据库,非关系型怎么理解呢,像mysql,oracle这都是关系型数据库,数据之间是存在某种关系的,而非关系型数据库存储的就是非结构化的海量数据,无法体现数据的关系。
redis的数据结构
redis不同于memcache的一点就是redis支持丰富的数据结构,而memcache只有string,下面我i们详细介绍一下,redis的五种数据结构,string,hash,list,set,zset。
string(字符串)
string是redis最基本的类型,也是非关系型数据库最基本的类型,结构就是 key-value
string是二进制安全的,意思就是他可以存储jpg图片和序列化的对象,最大能储存512MB
typedef char *sds;
struct sdshdr {
int len;// 记录 buf 数组中已使用字节的数量 等于 SDS 所保存字符串的长度
int free;// 记录 buf 数组中未使用字节的数量
char buf[];// 字节数组,用于保存字符串
};
虽说redis使用c语言写的,但是却不是c中的string类型,他是自己构建了一种名为简单动态字符串的抽象类型,我们可以观察他的源码实现,他的结构体中由三个部分,加入我们使用他保存一个“redis”,结构就是这样的:
len就是长度,buf数组用来保存字符串的每个元素,free记录了数组中未使用的字节容量
hash(字典)
hash就是一个键值对集合或者一个关联数组,是一个string类型的field和value的映射表,适合储存对象,每个key都是唯一的。
redis的字典使用哈希表作为底层实现,定义如下
typedef struct dictht{
//哈希表数组
dictEntry **table;
//哈希表大小
unsigned long size;
//哈希表大小掩码,用于计算索引值
//总是等于 size-1
unsigned long sizemask;
//该哈希表已有节点的数量
unsigned long used;
}dictht
哈希表是由数组 table 组成,table 中每个元素都是指向 dict.h/dictEntry 结构,dictEntry 结构定义如下:
typedef struct dictEntry{
//键
void *key;
//值
union{
void *val;
uint64_tu64;
int64_ts64;
}v;
//指向下一个哈希表节点,形成链表
struct dictEntry *next;
}dictEntry
key是用来保存键值,val用来保存值,值可以是指针,也可以是uint64_t整数,也可以是int64_t整数,还有一个指向下一个哈希节点的指针,是为了解决哈希冲突,解决方法有两种,一种是开放地址法,另一种就是拉链法,这里曹勇的就是后者,所以需要一个指向下一节点的指针
List(列表/双向链表)
list的实现其实就是一个双向链表,所以他支持左右插入即弹出,所以list一般用来做消息队列,看一下他的底层实现:
typedef struct listNode {
struct listNode *prev; //指向前一个节点
struct listNode *next; //指向后一个节点
void *value;//值
} listNode;//节点
typedef struct list {
listNode *head;//双向链表的头节点
listNode *tail;//双向链表的尾节点
void *(*dup)(void *ptr);//复制
void (*free)(void *ptr);//释放
int (*match)(void *ptr, void *key);//匹配
unsigned long len;//链表长度
} list;//双向链表/列表
typedef struct listIter {
listNode *next;//指向列表的某个节点
int direction;//迭代方向
} listIter;//访问链表的迭代器
总结一下list的特点:
1 双端:具有前置节点和后置节点的引用,可以直接获取
2 无环,前后都指向的null
3 带链表长度计数器,通过len属性获取链表的长度,时间复杂度为O(1)
4多态:链表节点使用void*作为指针保存节点值,可以保存各种不同的类型的节点的值
set(集合)
底层实现就是哈希,所以他是无序的,它相当于一个集合,所以他是不重复的,redis还提供了为集合求交集,并集,差集的操作,就可以实现共同好友,推荐好友等功能
zset(有序集合)
和set一样都是string类型元素的集合,且不允许有重复的元素,不同的就是每个元素都关联一个double类型的分数,redis就是通过这个分数来为集合中的元素进行排序
typedef struct zskiplistNode {
robj *obj; // 成员对象
double score;// 分值
struct zskiplistNode *backward; // 后退指针
struct zskiplistLevel {
struct zskiplistNode *forward; // 前进指针
unsigned int span;// 跨度
} level[]; // 层
} zskiplistNode;//有序集合的节点
typedef struct zskiplist {
struct zskiplistNode *header, *tail; // 表头节点和表尾节点
unsigned long length;// 表中节点的数量
int level;// 表中层数最大的节点的层数
} zskiplist;//有序集合
zset的底层其实是一个跳跃表结构
先简单介绍到这里,下一篇我会详细介绍一下hash和zset中的一些详细的知识点