Java技术债务Java技术债务

  •  首页
  •  分类
  •  归档
  •  标签
  • 博客日志
  • 资源分享
  •  友链
  •  关于本站
注册
登录

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

Redis

文章目录

  • string
  • list
  • hash
  • set
  • zset

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)但是无序
  • 虽然采用两个结构但是集合元素成员和分值时共享的,两种结构通过指针指向同一地址,不会浪费内存

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://cuizb.top/myblog/article/1641220204
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。
阅读全文
Java技术债务

Java技术债务

Java技术债务
Java技术债务
热门文章
  1. ClickHouse使用过程中的一些查询优化(六)2003
  2. MySQL数据库被攻击,被删库勒索,逼迫我使出洪荒之力进行恢复数据764
  3. MySQL主从同步原理458
  4. 线程池的理解以及使用414
  5. Spring Cloud Gateway整合nacos实战(三)409
分类
  • Java
    30篇
  • 设计模式
    27篇
  • 数据库
    20篇
  • Spring
    18篇
  • MySQL
    13篇
  • ClickHouse
    11篇
  • Kubernetes
    10篇
  • Redis
    9篇
  • Docker
    8篇
  • SpringBoot
    7篇
  • JVM
    6篇
  • Linux
    5篇
  • Spring Cloud
    5篇
  • 多线程
    5篇
  • Netty
    4篇
  • Kafka
    4篇
  • 面经
    4篇
  • Nginx
    3篇
  • JUC
    3篇
  • 随笔
    2篇
  • 分布式
    1篇
  • MyBatis
    1篇
  • 报错合集
    1篇
  • 生活记录
    1篇
  • 源码
    1篇
  • 性能优化
    1篇

最新评论

  • MySQL数据库被攻击,被删库勒索,逼迫我使出洪荒之力进行恢复数据2022-05-06
    Java技术债务:@capture 一起探讨学习,服务器被黑很正常,及时做好备份以及做好防护
  • MySQL数据库被攻击,被删库勒索,逼迫我使出洪荒之力进行恢复数据2022-04-13
    capture:我的刚上线两天,网站里就两篇文章也被攻击了,纳闷
  • Java常用集合List、Map、Set介绍以及一些面试问题2022-01-18
    Java技术债务:HashSet和TreeSet 相同点:数据不能重复 不同点: 1、底层存储结构不同; HashSet底层使用HashMap哈希表存储 TreeSet底层使用TreeMap树结构存储 2、唯一性方式不同 HashSet底层使用hashcode()和equal()方法判断 TreeSet底层使用Comparable接口的compareTo判断的 3、HashSet无序,TreeSet有序
  • undefined2021-12-14
    Java技术债务:如果不指定线程池,CompletableFuture会默认使用ForkJoin线程池,如果同一时间出现大量请求的话,会出现线程等待问题,建议使用自定义线程池。。。
  • undefined2021-12-02
    you:很好,对于小白相当不错了,谢谢
  • CSDN
  • 博客园
  • 程序猿DD
  • 纯洁的微笑
  • spring4all
  • 廖雪峰的官方网站
  • 猿天地
  • 泥瓦匠BYSocket
  • crossoverJie
  • 张先森个人博客
  • 越加网

© 2021-2022 Java技术债务 - Java技术债务 版权所有
总访问量 0 次 您是本文第 0 位童鞋
豫ICP备2021034516号
Java技术债务 豫公网安备 51011402000164号

微信公众号

Java技术债务
Java技术债务

专注于Spring,SpringBoot等后端技术探索

以及MySql数据库开发和Netty等后端流行框架学习

日志
分类
标签
RSS

有不足之处也希望各位前辈指出