Redis的应用非常广泛,现在互联网公司基本都有用到。Redis可以用作数据库,缓存,以及消息中间件。下面会分几个章节,对Redis作详细介绍
一、Redis简介
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
二、Redis的存储类型
1.字符串类型
Redis中最基本的数据类型,可以存储任何形式的字符串,包括二进制数据。一个字符类型件允许存储的最大容量是512M
内部数据结构
String类型通过int,SDS(simple dynamic string)作为存储结构,int用来存放整型数据,SDS用来存放字符串,字节,浮点型数据。在Redis源码中,为SDS定义了5sdshdr类型。
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; //表示当前sds的长度(单位是字节)
uint8_t alloc; //表示已为sds分配的内存大小(单位是字节)
unsigned char flags; //用一个字节表示当前sdshdr的类型,因为有sdshdr有五种类型,所以至少需要3位来表示000:sdshdr5,001:sdshdr8,010:sdshdr16,011:sdshdr32,100:sdshdr64。
char buf[]; //sds实际存放的位置
};
以上只是其中一种,还有sdshdr5,sdshdr16,sdshdr32,sdshdr64,目的是为了满足不同长度字符串可以使用不同大小的Header,从而节省内存。
2.列表类型
列表类型可以存储有序的字符串列表,常用的操作是想列表两端添加元素或者获得某一片段。
内部数据结构
Redis3.2之前,list底层是采用ziplist加linkedlist,当数据量或元素长度小的时候会用ziplist减小内存占用,否则会用linkedlist
Redis3.2之后,list底层会采用quicklist,只是每个节点ziplist,其实就是ziplist和quicklist,结构图如下:
3、hash类型
内部数据结构
dictEntry
维护一个key-value的值,同时保留相邻元素的指针,用来维护哈希桶的内部链
typedef struct dictEntry {
void *key;
union { //因为value有多种类型,所以value用了union来存储
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next; //下一个节点的地址,用来处理碰撞,所有分配到同一索引的元素通过next指针链接起来形成链表key和v都可以保存多种类型的数据
} dictEntry;
dicht
哈希表的核心,实现一个hash表会使用一个buckets存放dictEntry的地址,一般情况下通过hash(key)%len得到的值就是buckets的索引,这个值决定了我们要将此dictEntry节点放入buckets的哪个索引里,这个buckets实际上就是我们说的hash表。dict.h的dictht结构中table存放的就是buckets的地址
typedef struct dictht {
dictEntry **table; //buckets的地址
unsigned long size; //buckets的大小,总保持为 2^n
unsigned long sizemask;//掩码,用来计算hash值对应的buckets索引
unsigned long used; //当前dictht有多少个dictEntry节点
} dictht;
dict
只有一个dictht还不够,比如rehash、遍历hash等操作,所以redis定义了一个叫dict的结构以支持字典的各种操作,当dictht需要扩容/缩容时,用来管理dictht的迁移。
typedef struct dict {
dictType *type; //dictType里存放的是一堆工具函数的函数指针,
void *privdata; //保存type中的某些函数需要作为参数的数据
dictht ht[2]; //两个dictht,ht[0]平时用,ht[1] rehash时用
long rehashidx; //当前rehash到buckets的哪个索引,-1时表示非rehash状态
int iterators; //安全迭代器的计数。
} dict;