redis内存

前言

redis的所有的数据都存在内存中,所以如何合理高效的利用redis内存就变得非常的重要了。首先我们应该知道redis的内存主要消耗在什么地方,怎么管理内存,怎么做才能够让redis的内存优化。这样才能用更少的内存,存储更多的数据,降低成本。


叙述

在这里插入图片描述

内存消耗

我们可以使用info命令查看redis中的内存的消耗情况,查看redis内存消耗的相关指标,从而可以更好的分析内存。
在这里插入图片描述在这里插入图片描述

  • mem_fragmentation_ratio > 1 说明多出来的部分名没有用于数据存储,而是被内存碎片所消耗,相差越大,说明内存碎片率越严重。
  • mem_fragmentation_ratio < 1 一般出现在Redis内存交换(Swap)到硬盘导致(used_memory > 可用最大内存时,Redis会把旧的和不适用的数据写入到硬盘,这块空间就叫Swap空间),出现这种情况需要格外关注,硬盘速度远远慢于内存,Redis性能就会变得很差,甚至僵死。

内存消耗的划分

对象内存

  对象内存是redis内存中占用最大的一块,存储着所有的用户的数据。redis所有的数据都采用的是key-value型数据类型,每次创建键值对的时候,都要创建两个对象,key对象和value对象。key对象都是字符串,value对象的存储方式,包括五种数据类型:string,list,hash,set,zset。每种存储方式在使用的时候长度、数据类型不同,则占用的内存就不同。

缓冲内存

  主要包括:客户端缓冲、复制积压缓冲区、AOF缓冲区
客户端缓冲:普通的客户端的连接(大量连接),从客户端(主要是复制的时候,异地跨机房,或者主节点下有多个从节点),订阅客户端(发布订阅功能,生产大于消费就会造成积压)
复制积压缓冲:2.8版本之后提供的可重用的固定大小缓冲区用于实现部分复制功能,默认1MB,主要是在主从同步时用到。
AOF缓冲区:持久化用的,会先写入到缓冲区,然后根据响应的策略向磁盘进行同步,消耗的内存取决于写入的命令量和重写时间,通常很小。

内存碎片

  目前可选的分配器有jemalloc、glibc、tcmalloc默认jemalloc
出现高内存碎片问题的情况:大量的更新操作,比如append、setrange;大量的过期键删除,释放的空间无法得到有效利用
解决办法:数据对齐,安全重启(高可用/主从切换)。

自身内存

  主要指AOF/RDB重写时redis创建的子进程内存的消耗,linux具有写时复制技术,父子进程会共享相同的物理内存页,当父进程写请求时会对需要修改的页复制出一份副本来完成写操作。


管理内存

设置上限

  redis默认是无限使用内存。所以在使用的时候尽量的去配置maxmemory,给redis设置内存使用上限,防止因redis的无限使用造成系统内存耗尽。需注意的是maxmemory配置的是Redis实际使用的内存量,即used_memory,由于有内存碎片的存在,所以实际的内存使用比used_memory要大。
Redis可以动态的执行内存的调整:

config set maxmemory 6GB

配置内存回收策略

删除过期的对象

1. 过期键的删除
惰性删除:什么时候执行呢?就是在客户端读取带有超时属性的键时,如果已经超过键值设置的过期时间,则删除并返回空。这样做的目的是主要是为了节省CPU成本考虑,不需要单独维护TTL链表来处理过期键的删除。但是,如果单独使用这种存在一个问题,如果当前的键值永远不再被访问呢?就不删除了吗?那肯定不行,这就会造成内存泄漏的问题。那Redis是怎么解决的呢?Redis提供了一个定时任务的删除机制来做补充。
2. 定时任务删除
Redis内存维护了一个定时任务,默认是每秒运行10次。具体的逻辑图如下:
在这里插入图片描述

溢出控制策略

当Redis使用的内存达到上限maxmemory后,就会根据maxmemory-policy设置的相关策略进行对应的操作。


内存优化

Hashtable

Redis所有的数据存储都是Key-Value的数据类型。整体的结构是Redis自己实现的hashtable,Redis有两个hashtable存在,但是只有其中一个是用来存数据的,另一个hashtable的存在是为了在扩容的时候用的。通过采用渐进式的方式,把旧的hashtable中的数据逐渐的复制到另外一个hashtable中去。为什么采用渐进式呢?因为Redis是单线程的,扩容一直数据的迁移是很耗费时间的,所以迁移的过程是不能对Redis的其他使用造成影响。所以采用渐进式。

redisObect对象

Redis中所有的值对象内部定义都是redisObject结构体。
在这里插入图片描述

简单动态字符串(simple dynamic string,SDS)

在Redis中,字符串对象时经常用到的。Redis中字符串的结构也是Redis自己定义的结构。
在这里插入图片描述

编码优化

Redis有5中不同的存储格式:String,List,Hash,Set,Zset,但是不同的类型,在存储到Redis中时会有不同的底层数据结构实现。类似集合ArrayList的底层实现是数组,而Linkedlist的底层实现是链表结构一样,编码不同,则存储是占用的内存以及读写的效率也是不同的。
在这里插入图片描述
embstr与raw的区别
  在讲两种编码格式的区别之前,先讲点其他的,现代的计算机的结构上边在CPU和内存之间存在一个缓存结构,用来协调CPU的高效和访存的相对缓慢的矛盾。平时听到的L1 Cache,L2 Cache,L3 Cache就是这个缓存。当CPU要访问内存之前会先在缓存里面找一找看有没有,如果没有,就去内存找,找到之后放到缓存里面。这个缓存的最小单位一般是64字节,一次性缓存连续的64个字节,这个最小的单位称为缓存行。
  在Redis中,每个value对象都有一个redisObject对象头,对于Redis的字符串对象,当读取数据时,拿到*ptr指针,然后再去找到指向的SDS对象,如果这个对象距离很远,就会影响Redis读取的效率。因此在Redis中设计了一种特殊的编码结构,这种结构就是embstr,它把redisObject请求头和SDS对象紧紧地挨到一起,然后整体放到一个缓存行中去,这样,在查询的时候就可以直接从缓存中获取到相关的数据,提高了查询的效率。
在这里插入图片描述
   在上边也讲了,缓存行一般的长度为64字节,如果想要把对象存到缓存行中,首先整体的长度不得超过64字节,每个请求头redisObject占用16字节,而SDS至少有3个自己被占用,同时Redis中会以\0来作为结尾的标志,也占用一个字节,因此,留给可输入的数据的长度就成了(64-16-3-1)=44字节,当存储的数据长度超过了44字节,就会变成raw的编码形式。
在这里插入图片描述


小结

关于redis内存就先讲到这里了,继续加油。

感谢您的阅读~~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hi-Sunshine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值