- 存储类型与操作命令
| 类型(Type key) | 存储编码(OBJECT encoding key) | 实例命令 |
|---|---|---|
| zset | ziplist | zadd myzset 10 java 20 php 30 ruby 40 cpp 50 python |
| zset | skiplist | zadd myzset 20 xxxx(value超过64个字节) |
问题:Redis是如何决定存储ziplist还是skiplist?
答:在Redis配置文件有两个属性zset-max-ziplist-entries 128 ;zset-max-ziplist-value 64(字节),当集合内元素小于128,所有元素长度小于64字节使用ziplist,若无法满足ziplist条件时skiplist作为内部实现
问题:若存储的内分值相同Redis如何处理?
答:所有节点的分值是按从小到大的方式排序的,当有序集合的成员分值相同时,节点 会按ele(见下)的字典序进行排序
存储原理
- skiplist
typedef struct zskiplistNode {
sds ele;
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;
/**
* 有序集合结构体
*/
typedef struct zset {
/*
* Redis 会将跳跃表中所有的元素和分值组成
* key-value 的形式保存在字典中
* todo:注意:该字典并不是 Redis DB 中的字典,只属于有序集合
*/
dict *dict;
/*
* 底层指向的跳跃表的指针
*/
zskiplist *zsl;
} zset;
| 属性 | 说明 |
|---|---|
| ele | 用于存储字符串类型的数据 |
| score | 用于存储排序的分值 |
| backward | 后退指针,只能指向当前节点最底层的前一个节 点,头节点和第一个节点——backward指向NULL,从后向前遍历跳 跃表时使用 |
| level | 为柔性数组。每个节点的数组长度不一样,在生成跳跃 表节点时,随机生成一个1~64的值,值越大出现的概率越低 |
| forward | 指向本层下一个节点,尾节点的forward指向NULL |
| span | forward指向的节点与本节点之间的元素个数。span值越 大,跳过的节点个数越多;跨度实际上是用来计算元素排名(rank)的,在查找某个节点的过程中,将沿途访过的所有层的跨度累积起来,得到的结果就是目标节点在跳跃表中的排位 |
- 结构示意图
跳表具有如下性质: (1) 由很多层结构组成 (2) 每一层都是一个有序的链表 (3) 最底层(Level 1)的链表包含所有元素 (4) 如果一个元素出现在 Level i 的链表中,则它在 Level i 之下的链表也都会出现。 (5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。
应用场景
- 排行榜