Redis6-过期淘汰、经典数据类型的实现

一、redis的缓存过期淘汰策略

redis配置文件中有一个maxmemory,配置内存大小。默认是64位无限制,32位最大3GB。官网推荐配置是物理内存的四分之三。

查看redis内存使用情况,info memory:

1、如果超过了最大内存怎么办 

当超过最大内存之后,设置的时候,会提示OOM,所以会出现内存淘汰策略(LRU)

redis的key当过期了之后,不一定会立刻删除,需要根据不同清情况分析。

redis的内存删除方式:

  • 立刻删除:能够保证数据新鲜、内存空间释放,但是性能消耗很大
  • 惰性删除:过期后方位第一次删除,对内存不友好,但是性能消耗低
  • 定期删除:折中上面两个方式,定期清理过去数据,但是删除哪个数据、周期是多少需要确定

过期淘汰算法:

  • LRU(最近最少使用):优先淘汰最近未被使用的数据
  • LFU(使用频率最少):优先淘汰最近使用最少的数据

redis6的过期淘汰策略(8种):

名称策略的解释
noeviction默认策略,不淘汰数据
allKeys-lru所有key中,使用LRU算法(推荐)
allKeys-lfu所有key中,使用LFU算法
allKeys-random所有key中,使用随机淘汰
volatile-ttl设置过期key中,挑选出最早过期的key删除
volatile-lru设置过期key中,使用LRU算法
volatile-lfu设置过期key中,使用LFU算法
volatile-random设置过期key中,使用随机淘汰

二、redis经典五种属类型及底层实现

redis可以理解为都是所有的都是字典,key是String、value是redisObject。使用type命令可以看到bitmap类型是stirng、hyperloglog类型是string、GEO类型是zset。所以redis底层数据结构还是经典的五种类型。

RedisObject、五种数据类型、底层实现的关系:

在redis中,每个键值对都会对应一个dictEntry,存放了指向key、value、下一个dictEntry的指针,key是字符串但是使用redis自定义的SDS存放,而value存放在redisObject中。

redisObject的结构:

  • type:当前对象的数据类型
  • encoding:当前对象底层存储的编码类型
  • lru:采用LRU算法,记录对象最后访问的时间
  • refcount:对象引用次数
  • *ptr:指向真正底层数据结构的指针

2.1、String数据结构介绍

1、3大编码格式(为了精确的利用内存)

  • int:保存long型有符号整数,长度最多19位。
  • embstr:redis封装的格式SDS(简单动态字符),超过long型&&长度小于44字节的字符串
  • raw:redis封装的格式SDS(简单动态字符),保存长度大于44字符串

2、编码格式案例

3、SDS简单动态字符串简介

redis为什么不直接用c语言的字符串,而是自己建立了一套结构SDS,不满意效率。

  • c字符串获取长度,需要遍历char[],时间复杂度是o(N),SDS是o(1)
  • 内存重新分配问题,c字符串是char[]数组,扩容、缩容不方便
  • c字符串遇到'\0'就是结束,容易出现读取问题,二进制安全

SDS结构如下:

  • len:已用字节长度
  • alloc:字符串最大字节长度
  • flags:用来博鳌是SDS的类型,SDS8、SDS16、SDS32、SDS64
  • buf[]:真正的字符串

4、源码分析

Redis在启动的时候,会建立1万个0~9999的redisObject变量作为共享对象,这就意味着set字符串键在0~10000的时候,不需要建立对象直接使用共享对象。

 

embstr和raw不同的地方在于,embstr是内存连续的,raw是重新申请了一块内存,所以embstr会减少内存碎片的产生。还有一点,对embstr进行append,则会转换成raw。

2.2、Hash数据结构介绍

  • hash-max-ziplist-entries:使用压缩表保存时,hash集合中最大元素个数
  • hash-max-ziplist-value:使用缩缩表保存时,hash集合中单个元素最大长度

通过上图可知,hash默认数据类型是压缩表,当集合个数太大或者元素长度太大的时候,才会使用hashtable进行保存。可以升级,无法降级。

综上所述,hash数据结构存在2种:ziplist、hashtbale(几乎等价java种的hashtable)

压缩表(ziplist):双向链表,但是不存储指针

是一种紧凑的编码格式,压缩了数据,减少内存空间,但是需要压缩、解压写入、读取。也就是读写率换取空间。内存利用率极高的原因是连续的内存。所以当数据比较小的时候,使用压缩表最合适。

  • header:
    • zlbytes:所占内存字节数,用于重新分配和计算zlend
    • zltail:尾节点到起始地址有多少字节
    • zllen :节点数量
  • entry:节点
    • 前一个节点长度:用这个字段和总长度,就能计算出每个节点的位置
    • encoding
    • entry-data
  • zlend:0xff,用于标记压缩表的末端

优点:

  • 普通列表存在2个指针,有些数据可能还么有指针大,所以优化掉了指针内存,通过长度推算位置
  • 列表内存一般不连续,遍历速度慢,ziplist把相关偏移量记录在节点中,可以跳到上一个或下一个节点
  • 列表长度不在遍历,时间复杂度是O(1)

HashTbale:OBJ_ENCODING_HT是哈希表机构或者称为字典结构

 

2.3、List数据结构介绍

在低版本(3.2之前)的Redis中,list采用底层的数据结构是ziplist+linkedlist,而高版本的Redis中list的底层数据结构是quicklist,而quicklist也用到了ziplist。

quicklist是ziplist和linkedlist的混合体,他将linkedlist按段切分,每一段使用ziplist来紧凑存储,多个ziplist使用双向指针串起来。

  • list-compress-depth:1表示quicklist两端各有一个节点不压缩,中间节点压缩
  • list-max-ziplist-size:-1表示quicklist每个节点上的ziplist大小不能超过4K 

2.4、Set数据结构介绍

redis中用intset和hashset存储set,如果元素都是整型,就使用intset。否则使用hashset(数组+链表),其中key是元素,value是null。

2.5、ZSet数据结构介绍

Redis中使用ziplist和skiplist(跳表)来实现ZSet,当元素不满速上面的情况,就使用ziplist否则使用skiplist。

跳跃表(skiplist): 

由于普通的链表无法进行二分查找,因此借鉴数据库的索引思想,提取出链表中关键节点(索引),现在关键节点上查找,在进入下层链表查找。提取多层关键节点,就形成了skiplist。所以跳表=链表+多级索引(索引的索引),也就是给链表怎加索引,用空间换时间。

优化为,两两取首:

主要就是用多级索引能够快速查找,但是为什么是两两取首?既然决定了用空间,那么就让器粒度最低。

针对读多写少的情景,优点是查询块,缺点是浪费空间。 

2.6、小结

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值