前言
Redis的数据都存储在内存中,所以本篇文章将学习Redis的内存机制,以帮忙定位Redis的内存相干问题。
注释
一. 查看Redis中的内存
Redis提供了info memory
指令来查看Redis的内存状况,然而在查看Redis中的内存之前,先通过一段代码来造成Redis的OOM,代码片段如下。
long count = 0L;
while (true) {
byte[] bytes = new byte[1024];
RBucket<byte[]> curBucket = redissonClient.getBucket(String.valueOf(count++));
curBucket.set(bytes);
}
因为当时曾经将Redis的最大内存设置为了10MB
,所以上述代码片段运行一小会儿就会造成Redis产生OOM,Redisson
抛出的OOM异样如下。
此时应用info memory
指令查看Redis内存状况,如下所示。
下表是对上图的字段的阐明。
字段 | 阐明 |
---|---|
used_memory | Redis应用的内存总量。蕴含对象内存,缓冲内存,虚拟内存和本身内存,不蕴含内存碎片。 |
used_memory_rss | Redis过程占用的内存总量。蕴含对象内存,缓冲内存,本身内存和内存碎片,不蕴含虚拟内存。 |
used_memory_peak | used_memory达到过的峰值。 |
used_memory_lua | Lua引擎占用的内存。 |
maxmemory | 用户配置的Redis的最大内存。 |
maxmemory_policy | Redis达到最大内存时的淘汰策略。 |
mem_fragmentation_ratio | used_memory_rss / used_memory。代表Redis内存的碎片化率,值越大,示意Redis的内存碎片越多。 |
mem_allocator | Redis应用的内存分配器。默认为jemalloc。 |
注:以_human结尾的字段是增加了单位的可读形式显示。
二. used_memory详解
info memory
指令的后果中的used_memory示意Redis理论应用的内存,通常由对象内存,缓冲内存和本身内存组成,能够由下图进行概括。
1. 对象内存
已知Redis中存储数据时应用的键和值均为对象,Redis中的对象共五种(详见Redis-对象类型),当存储数据时,会依据存储场景将数据存储为不同的对象,此时Redis的内存分配器会为这些对象分配内存空间。
2. 缓冲内存
Redis中的缓冲区次要有:客户端缓冲区,AOF缓冲区和复制积压缓冲区,这些缓冲区的内存耗费能够概括如下。
- 客户端缓冲区:又分为客户端输出缓冲区和客户端输入缓冲区。客户端输出缓冲区用于暂存客户端输出的指令,当一次性写入大量指令,或者服务端负载过高时,客户端输出缓冲区会继续增高,客户端输出缓冲区的最大容量为
1GB
。客户端输入缓冲区用于保留指令执行后的返回后果; - AOF缓冲区:Redis进行AOF长久化时会先将Redis指令写入缓冲区中,而后再依据AOF的写磁盘策略在适合的工夫点将缓存内容刷到磁盘文件中;
- 复制积压缓冲区:用于主从同步。对于主从同步,会在后续的文章中介绍。
3. 本身内存
次要指进行RDB或者AOF长久化时,Redis创立子过程的内存耗费。
三. mem_fragmentation_ratio详解
mem_fragmentation_ratio示意Redis内存的碎片化率,所谓内存碎片,就是Redis占用着然而又没有用于存储数据的内存。mem_fragmentation_ratio = used_memory_rss / used_memory
,对于mem_fragmentation_ratio的值,存在如下的含意。
- mem_fragmentation_ratio大于1时,示意Redis存在内存碎片,mem_fragmentation_ratio越大,内存碎片越多;
- mem_fragmentation_ratio小于1时,示意Redis的局部内存替换到了磁盘(应用了虚拟内存),值越小,Redis替换到磁盘的内存就越多,此时Redis的速度就越慢。
失常状况下,mem_fragmentation_ratio的值须要大于1并管制在1.2以内。
Redis产生内存碎片是因为Redis的默认内存分配器jemalloc的内存分配机制导致的,jemalloc分配内存时,会依照如下规定。
- 调配的内存空间满足2的幂次方;
- 调配的内存空间满足大于等于须要调配的内存空间。
所以如果须要调配100byte
,那么jemalloc会调配128byte
的内存空间,此时Redis过程占用的这128byte
的内存理论只有100byte
被应用,未应用的28byte
就是内存碎片。同时如果一个128byte
的内存空间中只有局部数据被删除,那么这128byte
的内存是不会被回收的,此时也产生了内存碎片。
四. Redis的淘汰策略
如果Redis应用的内存将超过maxmemory时,Redis会依据maxmemory_policy即淘汰策略来决定将哪些数据淘汰掉。Redis反对的淘汰策略如下表所示。
淘汰策略 | 阐明 |
---|---|
noeviction | 默认策略。应用内存达到maxmemory时,如果增加新数据,不会删除任何旧数据,而是间接报错。 |
volatile-random | 对设置了过期工夫(expire )的数据失效。随机删除一部分数据,直到有足够的内存空间调配给新数据,如果将设置了过期工夫的数据全副删除完了都没有足够空间调配给新数据,此时报错。 |
volatile-ttl | 对设置了过期工夫(expire )的数据失效。优先删除过期工夫最小的数据,如果将设置了过期工夫的数据全副删除完了都没有足够空间调配给新数据,此时报错。 |
volatile-lru | 对设置了过期工夫(expire )的数据失效。应用LRU算法删除数据,如果将设置了过期工夫的数据全副删除完了都没有足够空间调配给新数据,此时报错。 |
volatile-lfu | 对设置了过期工夫(expire )的数据失效。应用LFU算法删除数据,如果将设置了过期工夫的数据全副删除完了都没有足够空间调配给新数据,此时报错。 |
allkeys-random | 对所有数据失效。随机删除一部分数据,直到有足够的内存空间调配给新数据,如果没有数据可供删除且还未有足够空间调配给新数据,此时报错。 |
allkeys-lru | 对所有数据失效。应用LRU算法删除数据,如果没有数据可供删除且还未有足够空间调配给新数据,此时报错。 |
allkeys-lfu | 对所有数据失效。应用LFU算法删除数据,如果没有数据可供删除且还未有足够空间调配给新数据,此时报错。 |
下面提到的LRU(Least Recently Used)算法其实就是将最近被拜访间隔以后最久的数据删除,Redis会记录每个数据最初一次被拜访的工夫,在须要删除数据开释空间时,会依据每个数据最初一次被拜访的工夫抉择出最“旧”的数据进行删除,所以LRU(Least Recently Used)算法有一个毛病,就是一个很少被拜访然而最近被拜访过的数据不会优先被删除,所以Redis4.0引入了LFU(Least Frequently Used)算法,即须要删除数据开释空间时,依据数据的拜访频次筛选出起码被拜访的数据进行删除,如果两条数据的拜访频次雷同,此时再依据数据最初一次被拜访工夫来决定删除哪条数据。
在第一节的例子中,能够看到Redis的淘汰策略是noeviction,所以在应用内存达到maxmemory后,Redis报了OOM的谬误。
五. Redis的过期策略
上一节提到在Redis中能够应用expire
指令为存储的数据设置过期工夫,那么某条数据过期后,Redis会依据过期策略来删除这些过期数据,Redis中的过期策略如下所示。
过期策略 | 阐明 |
---|---|
定时删除 | 每个设置了过期工夫的数据都有一个定时器,一旦数据过期,该数据会立刻被删除。长处:过期数据能够及时被删除;毛病:过期数据多时定时器会占用较多CPU资源。 |
惰性删除 | 应用数据的时候才去判断该数据是否过期,如果过期就删除该数据。长处:过期数据被拜访时才会被删除,删除过期数据不会占用过多CPU资源;毛病:有些曾经过期然而没有被拜访的数据会长期得不到删除。 |
定期删除 | 每隔一段时间扫描过期数据并删除。长处:通过管制扫描的间隔时间和执行工夫,能够缩小删除过期数据的操作对CPU资源的占用;毛病:扫描的间隔时间和执行工夫难以确定一个正当值。 |
在Redis中是采纳惰性删除加定期删除来解决过期数据的,同时Redis在进行定期删除时,是将设置了过期工夫的key寄存在字典中,默认状况下是每秒对字典进行10次扫描,每次扫描应用贪婪策略遍历局部key来判断对应的数据是否过期,贪婪策略如下。
- 步骤1:从字典中随机抉择20个key;
- 步骤2:删除这20个key中过期key对应的数据;
- 步骤3:如果20个key中过期key占比超过25%,则反复步骤1-3。
总结
Redis将数据寄存在内存中,所以理解Redis的内存机制对于应用Redis很有帮忙。info memory
指令可能列出Redis以后的内存情况和内存策略,能够通过maxmemory配置项来配置Redis的最大内存,也能够通过maxmemory-policy配置项来配置当内存达到最大值时的数据淘汰策略。Redis提供了共8种淘汰策略,能够仅针对设置了过期工夫的数据失效,也能够针对所有数据失效,如果不配置淘汰策略,那么Redis采纳的默认淘汰策略为不淘汰,此时内存达到最大值时Redis会报OOM谬误。
发表回复