Redis有5个基本数据结构,string、list、hash、set和zset
一、String
1、底层结构
简单动态字符串(SDS):
/*
* 保存字符串对象的结构
*/
struct sdshdr {
// buf 中已占用空间的长度
int len;
// buf 中剩余可用空间的长度
int free;
// 数据空间
char buf[];
};
特点:(和Java中ArrayList结构很像)
(1)引入了len属性,获取字符串长度的时间复杂度为O(1),防止数组越界。
(2)引入了free属性,自动扩容:
a)进行修改后len小于1M,程序将分配和len一样大小的free空间
b)进行修改后len大于1M,程序将分配1M空间
2、基本操作(包含其他基本操作)
默认Redis会创建16个数据库,默认为0号数据库,切换数据库:select 2
set key value//设置键值
get key //获取值
del key //删除键
exists key //判断键是否存在
keys pattern //查找符合pattern的key
setnx key value//只有在 key 不存在时设置 key 的值。
二、List
1、底层结构
双向链表:
链表节点定义:
typedef struct listNode{
struct listNode *prev;
struct listNode * next;
void * value;
}
链表定义:
ypedef struct list{
//表头节点
listNode * head;
//表尾节点
listNode * tail;
//链表长度
unsigned long len;
//节点值复制函数
void *(*dup) (void *ptr);
//节点值释放函数
void (*free) (void *ptr);
//节点值对比函数
int (*match)(void *ptr, void *key);
}
2、基本操作
LPUSH key value1 [value2] //将一个或多个值插入到列表头部
LPOP key //移出并获取列表的第一个元素
RPUSH key value1 [value2] //将一个或多个值插入到列表尾部
RPOP key //移除列表的最后一个元素,返回值为移除的元素。
BLPOP key1 [key2 ] timeout //移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOP key1 [key2 ] timeout //移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
LLEN key //获取列表长度
LRANGE key start stop //获取列表指定范围内的元素
3、应用
1.微博 TimeLine
2.消息队列
三、Hash
1、底层实现
字典(dict):
typedef struct dict {
// 类型特定函数
dictType *type;
// 私有数据
void *privedata;
// 哈希表
dictht ht[2];
// rehash 索引
in trehashidx;
}
解决Hash冲突:链地址法(和JDK1.7的HashMap一样)
rehash:
1)为ht[1]hash表分配空间
如果执行的是拓展操作,那么ht[1] 的大小为第一个大于等于ht[0] 的2的n次幂
如果执行的是收缩操作,那么ht[1] 的大小为第一个大于等于ht[0] 的2的n次幂
2)将ht[0]中的数据转移到ht[1]中,在转移的过程中,需要对哈希表节点的数据重新进行哈希值计算
渐进式Hash:并不是一次性转移,而是在每次执行添加等操作时慢慢转移,分摊每次操作成本。
3)将ht[0]释放,然后将ht[1]设置成ht[0],最后为ht[1]分配一个空白哈希表,为下一次rehash准备。
2、基本操作
HSET key field value // 将哈希表 key 中的字段 field 的值设为 value 。
HSETNX key field value //只有在字段 field 不存在时,设置哈希表字段的值。
HMSET key field1 value1 [field2 value2 ] //同时将多个 field-value (域-值)对设置到哈希表 key 中。
HGET key field //获取存储在哈希表中指定字段的值。
HEXISTS key field //查看哈希表 key 中,指定的字段是否存在.
HDEL key field1 [field2] //删除一个或多个哈希表字段
HGETALL key //获取在哈希表中指定 key 的所有字段和值
HKEYS key //获取哈希表中所有键
HVALS key //获取哈希表中所有值
HLEN key //获取哈希表大小
3、应用
存储、读取、修改用户属性
四、Set
1、底层实现
字典(dict)
2、基本操作
SADD key member1 [member2] //向集合添加一个或多个成员
SREM key member1 [member2] //向集合移除一个或多个成员
SMEMBERS key //返回集合中的所有成员
SCARD key //获取集合的成员数
SINTER key1 [key2] //求交集
SDIFF key1 [key2] //求差集
SUNION key1 [key2] //求并集
SPOP key //移除并返回集合中的一个随机元素
3、应用
1.共同好友、二度好友
2.抽奖
3.利用唯一性,可以统计访问网站的所有独立 IP
4.好友推荐的时候,根据 tag 求交集,大于某个 threshold 就可以推荐
五、ZSet(有序集合)
1、底层实现
跳表(skiplist):
跳表节点结构:
typedef struct zskiplistNode{
//层
struct zskiplistLevel{
//前进指针
struct zskiplistNode *forward;
//跨度
unsigned int span;
} level[];
//后退指针
struct zskiplistNode *backward;
//分值
double score;
//成员对象
robj *obj;
}
1、层:level 数组可以包含多个元素,每个元素都包含一个指向其他节点的指针。
2、前进指针:用于指向表尾方向的前进指针
3、跨度:用于记录两个节点之间的距离
4、后退指针:用于从表尾向表头方向访问节点
5、分值和成员:跳跃表中的所有节点都按分值从小到大排序。成员对象指向一个字符串,这个字符串对象保存着一个SDS值
跳表结构:
typedef struct zskiplist {
//表头节点和表尾节点
structz skiplistNode *header,*tail;
//表中节点数量
unsigned long length;
//表中层数最大的节点的层数
int level;
}zskiplist;
2、基本操作
ZADD key score1 member1 [score2 member2] //向有序集合添加一个或多个成员,或者更新已存在成员的分数
ZRANGEBYLEX key min max [LIMIT offset count] //通过字典区间返回有序集合的成员
ZCARD key //获取有序集合的成员数
ZCOUNT key min max //计算在有序集合中指定区间分数的成员数
ZRANK key member //返回有序集合中指定成员的索引
ZINCRBY key increment member //有序集合中对指定成员的分数加上增量 increment
ZREM key member [member ...] //移除有序集合中的一个或多个成员
ZSCORE key member //返回有序集中,成员的分数值
3、应用
带有权重的元素,比如一个游戏的用户得分排行榜
补充:当数据较少时,Redies内部用ziplist结构来实现list、hash、set和zset
示例: