您的位置:首页 > 理论基础 > 数据结构算法

redis的数据结构

2020-07-13 04:32 134 查看

Redis的基础数据结构分为5种,分别为:string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合)。熟练掌握这 5 种基本数据结构的使用是 Redis 知识最基础也最重要的部分。

String 字符串结构
String 字符串是动态字符串内部实现结构类似于Arraylist,采用预分配冗余的方式,减少内存空间的频繁分配。内部为字符串分配的空间会大于实际长度。当字符串长度小于1M,扩容都是加倍当前空间,大于1M则每次扩容增加1M,最大长度为512M。
其底层实现是简单动态字符串sds,一个sds字符串的完整结构由在内存地址前后两部分组成。第一,hearder。第二,字符数组。sds本质为char但是和char不相同的是sds是二进制安全的,可以存储任意二进制数据,不像c一样遇到’\0’来标识字符串的结束。另外其一种的header包含字符串长度,所以查询长度的复杂度为O(1)。

基本语法:
SET key value
1.字符串值 value 关联到 key 。
2.如果 key 已经持有其他值, SET 就覆写旧值,无视类型。

SETEX key seconds value
1.value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。
2.如果 key 已经存在, SETEX 命令将覆写旧值。

ETNX key value
1.将 key 的值设为 value ,当且仅当 key 不存在。
2.若给定的 key 已经存在,则 SETNX 不做任何动作。

使用场景:缓存信息,session,计数(bitmap)

List 列表结构
List列表3.2之前LinkList和ziplink,3.2之后改为qucklink,是一个按照插入顺序排序的链表。在3.2版本之前,如果list数据的长度较少,或者数据量不多用ziplink,如果过大,则用双向链表。Ziplink存放在一段连续的内存中,存储效率高,但是删除和插入就需要频繁申请内存和释放内存。如果数据长度很长 可能会导致realloc(内存分配)时候大批量拷贝数据。Linklist的push和pop操作使插入节点上复杂度很低。但是内存开销大,在每个节点上要保存数据外,还要保存额外两个指针记录前后标识。其次,各个节点都是单独内存块,不连续,容易产生内存碎片。Qucklink的每个节点都是Ziplink。Redis的参数list-max-ziplist-size可以设置,默认-2 ,8kb。对于内部压缩算法为LZF,无损压缩算法。
通常做异步队列,将需要延后处理的任务结构体序列化存进redis的列表,然后在另一线程中取出进行业务处理
Redis的list数据结构常用来作为异步消息队列使用,使用rpush/lpush操作入队列,使用lpop 和 rpop来出队列。

如图:右进左出为队列

Hash 结构
Redis的Hash内部是数组加链表的结构和hsahmap相同。但是redis的值只能是字符串。还有一点不同的是java的HashMap采用的一次性扩容的方式,而Redis为了高性能,采用渐进式策略。渐进式的rehash会在rehash的时候保留新旧hash结构,然后再后续的hash操作中逐渐将旧hash迁徙到新hash上,当迁徙完成旧hash会被删除,内存被回收。
Rehash介绍:当hash表保存的键较多或者较少时,哈希表会进行扩容或者缩减。在逐渐式rehash时,hash表会同时使用ht[0],ht[1]。字典的curd都会在这两个表进行。如果是新增只会新增在新表,这样保证旧表只会随着rehash或进行删除操作减少。最终变为空表,被回收释放内存。


使用场景:商品展示(用于两层嵌套场景。比如一个商品多重类型,每个类型多重样式)
也能用来存储用户信息。(可以对用户结构的每个字段单独存储,获取时不像String一样序列化整个字符串,可以单独读取部分)

Set结构
Set是一种无序不重复的集合。

使用场景:抽奖(确保不重复中奖)

Zset 结构
Zset集合一方面是个set,保证了唯一性。另一方面它给内部的value赋了一个score,代表这个value的排序权重。排序功能是通过跳跃列表的数据结构实现的。Zset内部数据结构可以是ziplist或者skiplist。
当满足元素数量小于128和所有menber长度小于64字节,使用ziplist。当然,可以通过修改zset-max-ziplist-entries和zset-max-ziplist-value来修改上限阈值。Ziplist使用紧挨在一起的压缩列表节点保存。第一个节点保存menber,第二个节点保存score。内部按照score从小到大排序,小的排在表头。
skipList内部结构是zset结构体。一个zset包含hash和一个跳跃表。跳跃表按照score进行从小到大的排序。而hash则保存menber和score的映射。这样通过menber查询score复杂度为O(1),虽然是使用了两个结构,但是是通过指针来共享menber和score,并不会造成内存的浪费。


使用场景:粉丝列表(key 为id,value为时间排序),订单列表

参考书籍:
《Redis深度历险:核心原理与运用实践》
《redis设计与实现》

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: