当前位置:网站首页>Redis的常用数据结构和底层实现方式

Redis的常用数据结构和底层实现方式

2022-08-09 11:12:00 Java技术债务

目录

string

存储方式 key-value,可支持数字,性能高,

用处 微博数,粉丝数

基本命令

set key value
get key
getrange key start end #返回key中字符串值的从start到end的字符
mget key1 key2 key3… #获取一个或多个key的值
setex key seconds value #将值关联到key并且设置key的过期时间(以秒为单位)
setnx key value #当key不存在时设置key的值
decr key #将key存储的数字减一
append key value #如果key是已存在的字符串,则在value末位后追加字符串

底层实现 String底层是动态字符串SDS(simple dynamic string) SDS结构有五种header定义,为了满足不同长度字符串可以使用不同大小的header,节省内存。

  • len:字符串真正长度。
  • alloc:字符串的最大容量
  • flags:标识为,第三位表示类型,其余5位未使用
  • buf:字符数组
  • encoding可能是int,raw,embstr
  • int:可以用long类型整数表示,redis会将键值转long类型存储
  • raw:长度大于44字节的字符串,使用SDS保存
  • embstr:长度小于等于44字节的字符串,效率高,且数据都保存在一块内存区域

list

双链表实现,可以支持队列机制,或者存储按时间顺序排序的某些信息,支持反向查找和遍历微博的关注列表、粉丝列表、消息列表等

常用命令

LPUSHX key value #将一个值插入到已存在的列表头部
LPUSH key value1 [value2] #将一个或多个值插入到列表头部
LPOP key #移出并获取列表的第一个元素
LLEN key #获取列表长度

list底层链表 早期使用ziplist或者linkedlist,redis3.2版本后list使用quickList

  • ziplist: 压缩列表,适用于长度较小的值,是由连续空间组成,保存每个值的长度信息,一次可查找每个值。存储效率高,内存小,但是由于是连续内存,修改需要重新分配内存
  • linkedlist: 双向链表,修改效率高,,但是由于需要保护前后指针,占用内存较多。
  • quicklist: 3.2版本后,quicklist是一种混合结构,ziplist和linkedlist的混合体,将linkedlist安段切分,每一段使用ziplist紧凑存储,多个ziplist之间使用双向指针串联起来,既满足快速插入删除性能,页不会出现太大的空间冗余。

hash

存储对象数据,可以直接读取或修改特定属性的值,可应用于redis分布式锁

存放用户信息,商品信息

注意:不要全部取整个hash,性能开销比较大,不推荐做复杂查询,会增加维护成本

常用命令

HDEL key field1 [field2] #删除一个或多个哈希表字段
HEXISTS key field #查看哈希表 key 中,指定的字段是否存在。
HGET key field #获取存储在哈希表中指定字段的值。
HGETALL key #获取在哈希表中指定 key 的所有字段和值
HINCRBY key field increment #为哈希表 key 中的指定字段的整数值加上增量 increment 。
HMGET key field1 [field2] #获取所有给定字段的值

HSET key field value #将哈希表 key 中的字段 field 的值设为 value 。
HSETNX key field value #只有在字段 field 不存在时,设置哈希表字段的值。

底层实现 hash底层是dict encoding使用ziplist和hashtable

  • ziplist: 当键和值的长度和数量比较少时,默认使用ziplist,hash过程是直接通过遍历得到,数据量小,效率高。
  • hashtable 采用hash表提高效率

set

不重复数据的集合,如订阅、关注用户id等信息 存放微博的关注人,粉丝人,快速找到共同好友

常用命令

SADD key member1 [member2] #向集合添加一个或多个成员
SINTER key1 [key2] #返回给定所有集合的交集
SUNION key1 [key2] #返回所有给定集合的并集

底层实现 encoding使用intset和hashtable

  • intset: 集合中的数都是整数时,数据量不超过512个,使用intset,有序不重复连续空间。节省空间,但是是连续空间,所以修改效率不高
  • hashtable value使用null填充。

zset

有序集合,带权重的集合,可以根据权重进行排序或查找和set相⽐,sorted set增加了⼀个权重参数score,使得集合中的元素能够按score进⾏有序排列。

存放直播间的在线用户列表,以及用户送的礼物,弹幕消息等。

常用命令

ZADD key score1 member1 [score2 member2] #向有序集合添加一个或多个成员,或者更新已存在成员的分数
ZREM key member [member ...] #移除有序集合中的一个或多个成员
ZCARD key #获取有序集合的成员数
ZCOUNT key min max #计算在有序集合中指定区间分数的成员数
ZINCRBY key increment member #有序集合中对指定成员的分数加上增量 increment

底层实现 encoding使用ziplist或者skiplist

  • ziplist 连续存放值以及score(排序的标准,double)当元素个数以及长度都比较小时使用
  • skiplist
    • 跳表(具有层次结构的链表),可支持范围查询
    • 查找和插入的时间复杂度都是log(n)
    • 使用一个dict保存每个值对应的score
    • 查找时,从开始查找,知道找到大于或者null的然后指向节点的下一层。
    • 新增时,为了保证每层的数量能够满足要求,需要随机产生该数的层数,并保证概率。
    • 删除时,需要考虑前驱的next节点改变,同时考虑最大level是否变化。

为什么使用跳表skiplist

  • 占用的内存开销可控(通知控制概率P)
  • 支持范围查询,比如zrange
  • 跳表优点时有序,但是查询分值复杂度时O(logn);字典查询分值复杂度为O(1)但是无序
  • 虽然采用两个结构但是集合元素成员和分值时共享的,两种结构通过指针指向同一地址,不会浪费内存
原网站

版权声明
本文为[Java技术债务]所创,转载请带上原文链接,感谢
https://cloud.tencent.com/developer/article/2068509