Redis源码-Set:Redis Set存储原理、Redis Set集合操作命令、Redis Set两种存储底层编码intset+hashtable、Redis Set应用场景
Redis数据类型
Redis数据类型不等同与数据结构,数据结构是Redis该数据类型存储结构的存储原理,也是该数据类型的底层编码。
1.Set存储原理
Redis Set存储的是无序的字符串(String和Hash也是无序的,List和zset是有序的),元素不能重复。
最大存储数量2^32-1(40亿左右元素数量)。
列表list、集合set、有序集合zset差异
数据结构 | 是否允许重复元素 | 是否有序 | 有序实现方式 |
---|---|---|---|
列表list | 是 | 是 | 索引下标 |
集合set | 否 | 否 | - |
有序集合zset | 否 | 是 | 分值score |
2.1Redis-Set数据类型:操作命令
Set的命令都是前面+s开头的。
放入集合多个元素
# sadd key member [member ...]:放入集合多个元素,返回集合大小
127.0.0.1:6379> sadd myset aa bb cc dd
(integer) 4
查看集合元素内容
# smembers key:查看集合元素内容
127.0.0.1:6379> smembers myset
1) "dd"
2) "bb"
3) "aa"
4) "cc"
统计集合元素个数
# scard key
127.0.0.1:6379> scard myset
(integer) 4
随机获取集合的元素
# srandmember key [count]:随机获取集合的元素,count为随机获取的个数,默认1
127.0.0.1:6379> srandmember myset
"bb"
127.0.0.1:6379> srandmember myset 2
1) "bb"
2) "dd"
弹出集合的元素(无序的,因此是随机弹,也是删除)
# spop key [count]:弹出集合的元素(无序的,因此是随机弹,也是删除),count为随机获取的个数,默认1
127.0.0.1:6379> spop myset
"aa"
127.0.0.1:6379> spop myset 2
1) "cc"
2) "dd"
删除指定的元素
# srem key member [member ...]:多个元素空格隔开
# 返回删除成功的个数
127.0.0.1:6379> sadd myset aa bb jj kk ll
(integer) 5
127.0.0.1:6379> srem myset aa bb oo
(integer) 2
判断集合是否存在元素
# sismember key member:判断集合是否存在元素,存在返回1,不存在返回0
127.0.0.1:6379> sismember myset jj
(integer) 1
127.0.0.1:6379> sismember myset 99
(integer) 0
2.2Redis-Set数据类型:集合操作命令(差集、并集、交集)
set1{a,b,c} set2{c,d,e}
获取差集:
sdiff set1 set2 {a,b,d,e}
获取交集:(intersection)
sinter set1 set2 {c}
获取并集:
sunion set1 set2 {a,b,c,d,e}
查看Redis内部的数据结构类型
当你插入Redis一个字符串数据时,会根据你插入的值,Redis再进行内部的数据转换。
可以先看本文目录:3.存储原理(底层编码)
可以用object encoding key名查看key的value再Redis的内部数据类型。
# 查看key在Redis的对内数据类型
127.0.0.1:6379> object encoding myset
"hashtable"
3.存储原理(底层编码)
Redis源码:Redis源码怎么查看入门、Redis外部数据结构到Redis内部数据结构查看源码顺序、Redis源码查看顺序
Redis Set两种底层编码类型:intset、hashtable
Redis Set类型的内部底层编码有两种:
根据存储内容的不同大小采取合适的编码,从而达到更好的效果
- intset,存储纯数字的情况下才会用到
- hashtable,OBJ_ENCODING_HT(哈希表,和Redis外层的Hash是一个)
Redis Set底层编码类型①:intset
intset编码只有存储纯数字的情况下才会用到
intset.h源码文件
intset.h源码文件在解压后的src目录下
typedef struct intset {
uint32_t encoding; // 编码类型 int_16t、int_32t、int_64t、
uint32_t length; // 长度 最大长度2^32 (40亿左右)
int8_t contents[]; // 用来存储成员的动态数组
} intset;
Redis Set底层编码类型②:hashtable
首先需要搞明白Redis外层的Hash表是什么。
Redis中的Hash结构,在Redis中,所有的KV存储方式都是基于dict(外层Hash表,HashTable)这个结构去存存储的,那么如果value的编码类型也是hashtable,应该怎么存储,其实就是hashtable的嵌套结构。
不理解dict结构、外层Hash、dict、dictht、dictEntry可以去看:
Redis源码:Redis源码怎么查看、Redis源码查看顺序、Redis外部数据结构到Redis内部数据结构查看源码顺序、Redis KV存储方式都是基于dict
Redis的KV存储方式-dict、dictht、dictEntry关系图
在Redis中,所有的KV存储方式都是基于dict(外层Hash表,HashTable)这个结构去存储的。
外层的KV存储的HashTable(dict),结构如下
Redis 底层编码类型hashtable嵌套结构图
总体存储结构为:【dictEntry有序链表】→【放在dictEntry数组里面】→【dictEntry数组放在dictht(哈希表ht[0])里面】→【dictht又放在dict结构里面】
Hash的扩容
扩容怎么扩容的?
判断的条件:
扩容比例(源码dict.c中定义):
static unsigned int dict_force_resize_ratio = 5; /*
dictEntry数组后面的dictEntry链表,
所有节点的链表平均值超过一定程度(会计算dictEntry链表长度和dictEntry的长度的比例,这个值为5),
也就表示hash碰撞很严重,就会触发扩容。
*/
dictEntry数组后面的dictEntry链表,所有节点的链表平均值超过一定程度(会计算dictEntry链表长度和dictEntry的长度的比例,源码中这个值为5),也就表示hash碰撞很严重,就会触发扩容。
扩容的量级是原dictht的2的n次方,扩容之后,会把原表的数据重新分配到新表(rehash,重新计算hash),然后用ht[0]标记为当前使用的是哪个表,清空原先的dictht来释放空间。
4.应用场景
- 抽奖:spop myset
- 唯一性记录:点赞、签到、打卡(用户记录)
- 商品标签、用户画像(人口属性、信用属性、社交、爱好…)
- 用户关注、推荐模型
- 基于集合的商品类别筛选
唯一性记录:点赞、签到、打卡(用户记录)
即用被点赞的记录作为key,用户作为set 的value进行维护。商品标签也是同样的道理。
用key(zan:v1001)来维护这条记录的所有点赞用户
用户u0001的点赞了这个记录:sadd zan:v1001 u0001
用户u0001的取消点赞这个记录:srem zan:v1001 u0001
用户u0001是否点赞了这个记录:sismember zan:v1001 u0001
这个记录点赞的所有用户:smembers zan:v1001
这个记录总点赞数:scard zan:v1001
基于集合的商品类别筛选
搜一款手机筛选条件如下:品牌ROG、机身内存1TB、CPU型号骁龙8+ Gen 1
可以用Redis set来实现
# sadd key (brand:ROG) value 该品牌手机型号
sadd brand:ROG ROG5s ROG6 ROG6pro ROG2 ROG3
# sadd key (cpud的分类key:cpu:8+Gen1) value 手机型号
sadd cpu:8+Gen1 ROG6 ROG6pro
sadd cpu:888 ROG5
# sadd key (ram的分类key:ram:1TB) value 手机型号
sadd ram:1TB ROG6 ROG6pro
# 搜一款手机筛选条件如下:品牌ROG、机身内存1TB、CPU型号骁龙8+ Gen 1
sinter brand:ROG cpu:8+Gen1 ram:1TB
Redis各数据结构命令、源码分析、应用场景
Redis源码-String:Redis String命令、Redis String存储原理、Redis String三种编码类型、Redis字符串SDS源码解析、Redis String应用场景
Redis源码-Hash:Redis String与Hash的区别、Redis Hash存储原理、Redis Hash命令、 Redis Hash存储底层编码、Redis Hash应用场景
Redis源码-List:Redis List存储原理、Redis List命令、 Redis List存储底层编码quicklist、Redis List应用场景
Redis源码-Set:Redis Set存储原理、Redis Set集合操作命令、Redis Set两种存储底层编码intset+hashtable、Redis Set应用场景
Redis源码-ZSet:Redis ZSet存储原理、Redis ZSet命令、 Redis ZSet两种存储底层编码ziplist/dict+skiplist、Redis ZSet应用场景