Redis---五种键值对实现
《Redis设计与实现》读书笔记
在Redis中的五种键值对⾥⾯,没有⼀个是单独使⽤基本的数据结构实现的,⽽是基于这个数据结构创建了⼀个对象系统,这个系统包含了:String字符串对象,List列表对象,哈希对象,集合对象,有序集合对象。(也是就⼴义的Redis五种基本数据结构)
Redis在执⾏命令之前,根据对象的类型来判断⼀个对象是否可以执⾏给定的命令。使⽤对象的另外⼀个好处是,我们可以针对不同的使⽤场景,为对象设置多种不同的数据结构实现,从⽽优化对象在不同环境下的使⽤效率。
redis是使⽤c语⾔来写的,key-value型NoSQL数据库。
Key命名规范,没有什么限制,叫什么都可以,但是有建议:Key不要太长,不要超过2014字节,消耗内存,⽽且会降低查的效率。在⼀个项⽬中,最好使⽤统⼀命名规范。区分⼤⼩写。
对象的类型与编码
Redis使⽤对象来表⽰数据库中的键和值,每次当我们在Redis的数据库中新创建⼀个键值对时,我们⾄少会创建两个对象,键都是string类型的,⽽value是五种类型之⼀。
value由结构redisObject表⽰:
typedef struct redisObject{
unsigned type:4;//类型
unsigned encoding:4;//编码
void *ptr;//指向底层实现数据结构的指针。
...
}robj;
type:记录对象的类型,值是五个常量中的⼀个(常说的五种类型),对于键值对来说,键总是字符串,值就是五个中的⼀个,所以我们只⽤关⼼值的类型。
ptr:指针指向对象的底层实现数据结构,具体的数据结构由encoding决定
encoding:对象所使⽤的编码,⽤什么数据结构作为底层实现,也是⼀个常量,每种类型的对象都⾄少只有了两种不同的编码:
根据值的不同情况(⽐如说,⼩,⼤,多,少等等情况下)底层的实现数据结构是不同的。
⼀,字符串 string
对象的编码有三种⽅式:int,raw,embstr。
1.如果⼀个字符串对象保存的是整数值,那么可以使⽤int类型,
2.如果是个字符串,并且长度>32字节,那么就使⽤SDS来保存(raw),
3.如果字符串<32字节,那么使⽤embstr优化编码⽅式,它与第⼆种情况的不同是:第⼆种情况会创建两个对象,⼀个是
redisObject(就是上⾯那个代码),还有⼀个是SDS(redis封装的字符串),他们两个是分开创建的,⽤⼀个指针相连,但是第⼆种它就节省了,⼀次性把两个对象的空间都分配好,然后把两个对象放在⼀起。
利⽤的是缓存⾏的概念,⼀个缓存⾏64byte,如果数据⽐较⼩,可以把redisObject和数据data放在⼀起。
编码之间的转换:保存⼀个long double类型的浮点数到redis中,redis是先把它保存为字符串的,在需要使⽤的时候,会转换为long double类型进⾏使⽤(⽐如基本运算 + - ),然后⼜保存为字符串。
⽽且embstr是只读的,如果要修改,redis会把embstr转换为raw,修改完毕,直接保存为raw。
使⽤: 1.赋值 set key value
2.检验键值是否存在 exists key (返回false或者true)
3.删除键 del key
4.节省⽹络耗时开销,批量写,读,mget key1 key2 key3 返回⼀个列表。
5. incr key ⾃增/⾃减;
6. append key value 如果key是 字符串,则将value拼接到key后⾯
应⽤场景:通常⽤于保存单个字符串 or json字符串数据。
⼆进制安全, 所以可以把⼀个图⽚作为字符串存储。
计数器(常规计数,粉丝数)使⽤⾃增来 投票等等。
三,哈希 hash
编码⽅式:ziplist,hashtable(字典)
ziplist编码的哈希对象使⽤压缩列表作为底层实现,当有新的键值对要加⼊到哈希对象时,程序先将保存了键的压缩列表节点推⼊到压缩列表表尾,然后再将保存了值的压缩列表节点推⼊到压缩列表表尾。所:同⼀个键值对的两个点,总是挨在⼀起的,先⼊的哈希对象是在表头的。
hashtable实现⽅式:
编码转换:哈希对象保存的所有键值对的键和值长度都要<64字节,哈希对象保存的键值对数量<512个,不能满⾜这两个都使⽤hashtable。
如果超过了这个条件按,ziplist就会转变成为hashtable。
使⽤:hset name field value hmset也可以多个value。hget
应⽤场景: 常⽤来存储⼀个对象,最接近关系型数据库,使⽤String序列化增加了编码解码的时间,吧对象转换为hashMap更快。四,集合 set
编码⽅式:intset或者hashtable
编码转换:集合对象保存的都是整数,保存的元素数量不超过512个,那么就使⽤intset来存放,破除了就使⽤hashtable来存放。
应⽤场景:对两个集合间的数据计算进⾏交集,并集,差集运算。
对不同兴趣圈的交集,到共同关注,还有共同好友。利⽤唯⼀性,统计访问完整的所有独⽴ip,存储当天的活跃⽤户列表。五,有序集合 sortSet
编码⽅式:ziplist或者skiplist,使⽤跳跃表来实现有序性,⽽且跳跃表的对象是唯⼀的,也能实现集合
的唯⼀性。压缩列表实现,使⽤两个节点来保存⼀个对象(成员-分值),压缩列表的集合元素也按分值从⼩到⼤排序。
跳跃表编码的有序集合使⽤zset结构作为底层实现,⼀个zset同时包含⼀个字典和⼀个跳跃表。
typedef struct zset{
zskiplist *zsl;
dict *dict;
}zset;
每个跳跃表节点都保存了⼀个集合元素,dict为有序集合创建了以恶搞从成员到分值的映射,键保存元素的成员,值保存分值,通过字典,可以O(1)⽅式通过成员查分值,两个结构会共享⾥⾯的数据。不会浪费额外空间。
编码转换:当有序集合保存的元素数量<128个,成员长度<64字节,那么就使⽤ziplist编码,否者使⽤skiplist编码。
应⽤场景:积分排⾏榜。
总结:
图⽚转⾃:
六,Redis数据库整体认识
⾥⾯的结构dict 就是字典
dict:进⾏索引操作
expires: 过期时间
blocking_keys:阻塞,与client进⾏交互
字典的结构:
dictht就是⼀个hashtable
table指向hash数组
数组中的存储节点:
redis八种数据结构包含了key -value-next 三个重要信息
key永远都是字符串类型
⽽val,由redisObject进⾏封装,它具有五种数据类型string ,list,hash,set ,zset.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论