民工哥的Redis教程(十八):内存消耗与回收
Redis是一个开源的高性能键值数据库,广泛应用于各种服务器场景。 Redis是一种内存数据库,将数据存储在内存中,其读写效率比将数据存储在磁盘上的传统数据库要快得多。因此,监控Redis内存消耗、了解Redis内存模型对于高效、长期稳定使用Redis至关重要。
在开始之前先解释一下。一般生产环境中,开发同事是不允许直接连接redis集群的。一般提供daas平台,通过可视化命令窗口输入redis命令。一般情况下只有读权限;对于写入操作,需要输入改变redis数据的命令。对于redis内存大、按键大、命令慢的情况,一般都会将信息整合显示在监控板上,不需要开发同事自己输入命令;但仍然需要基本的相关知识。从
reids内存分析
redis内存使用情况:信息内存示例:
可以看出当前节点的内存碎片率为226893824/200 oc使用的内存为1.0mal。地点由于内存碎片的存在,
used_memory_rss 通常会大于used_memory。
但是,当操作系统将redis内存替换为硬盘时,memory_fragmentation_ratio将小于1。Redis使用硬盘作为内存。由于硬盘速度的原因,redis的性能会受到很大的影响。
redis 内存使用情况
redis 内存使用情况分布:本机内存、键值对象占用、缓存占用、内存碎片占用。
redis 空进程本身消耗很少,可以忽略。优化内存时可以忽略这些因素。
对象内存
对象内存,即当前存储数据占用的内存。
redis k-v结构存储,对象占用可以简单理解为k-size + v-size。
所有Redis键都是字符串类型,值包括多种类型:字符串、列表、散列、集合、zset、五种基本类型,以及基于字符串的位图和HyperLogLog类型。
在实际应用中,内存kv的结构形式和使用期望一定要做好准备。
缓存
缓存由三部分组成:客户端缓存、backlog 缓存和 AOF 缓存。
客户端缓冲区
redis服务器占用的TCP连接的输入输出缓冲区繁忙。 TCP输入缓冲区占用不受控制,允许的最大空间为1G。可以使用 client-output-buffer-limit 参数配置输出缓冲区占用率。
Redis 客户端主要分为从属客户端、订阅者和普通客户端。
- 从客户端连接采用
,我们称之为从。主节点为每个子节点建立连接以复制命令。缓冲区配置为: client-output-buffer-limit Slave 256mb 64mb 60 。
主从之间的网络延迟以及连接的从节点数量是影响内存使用的主要因素。因此,要特别注意主人和奴隶在不同地点的安置。此外,避免每个主节点安装太多子节点(used_memory。
另外,您还可以使用动态配置maxmemory来主动触发内存回收。更多学习Redis的文章请参见:NoSQL数据库系列-Redis。该系列不断更新。
内存回收策略
触发内存回收有两种情况,一种是当内存使用达到最大内存上限时触发溢出回收,另一种是当我们设置时触发过期释放过期对象过期。内存回收。 当Redis内存使用达到最大内存限制时,触发溢出回收; Redis 提供了几种策略(maxmemory-policy),允许用户决定如何释放新的空间来继续提供读写服务:
- (1) volatile-lru:从数据集中选择最近最少使用的数据 (
server.db[i].expires
)其有效期已被设置为过期 - (2) volatile-ttl: 从设置的过期时间中选择有效期将过期的数据从具有过期时间的数据集中选择(
server.db[i].expires
) 并消除它 - (3) 易失性随机:来自具有设定过期时间的数据集 (
Server.db[i] ❀ )随机选择数据删除
- (4)allkeys-lru:如果内存不足以存放新写入的数据,则删除键空间中最近最少使用的key(这是最常用的)
- (5) allkeys-random: 从数据文件 (
server.db[i].dict
) 中随机选择数据以删除 - (6) no-eviction : 禁用数据驱逐,这意味着当内存不足以存放新写入的数据时,新记录的操作会报错。没有人应该使用它!
- 4.0版本后,增加了以下两种类型:
- (7) volatile-lfu:从数据集中选择出现频率最低的一种(
server.db[i].expires
)有效期设置 已使用数据的淘汰 - (8)allkeys-lfu:当内存不足以存储新写入的数据时,移除密钥空间中最不常用的密钥。默认的redis策略是neeviction。配置它需要在配置文件中写入这样的配置:
maxmemory-policy volatile-lru
LRU Redis 算法
LRU 是最近最少使用的算法。许多缓存策略都使用此策略来释放空间。我正在学习这种机制也被用来回收操作系统中的内存。类似的还有LFU(LeastFrequentlyUsed)算法,即最不常用的算法。
从上面的描述中我们还可以了解到,redis使用类似LRU的算法来从内存溢出中恢复。算法代码:
/* volatile-lru and allkeys-lru policy */ else if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU || server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU) { struct evictionPoolEntry *pool = db->eviction_pool; while(bestkey == NULL) { evictionPoolPopulate(dict, db->dict, db->eviction_pool); /* Go backward from best to worst element to evict. */ for (k = REDIS_EVICTION_POOL_SIZE-1; k >= 0; k--) { if (pool[k].key == NULL) continue; de = dictFind(dict,pool[k].key); /* Remove the entry from the pool. */ sdsfree(pool[k].key); /* Shift all elements on its right to left. */ memmove(pool+k,pool+k+1, sizeof(pool[0])*(REDIS_EVICTION_POOL_SIZE-k-1)); /* Clear the element on the right which is empty * since we shifted one position to the left. */ pool[REDIS_EVICTION_POOL_SIZE-1].key = NULL; pool[REDIS_EVICTION_POOL_SIZE-1].idle = 0; /* If the key exists, is our pick. Otherwise it is * a ghost and we need to try the next element. */ if (de) { bestkey = dictGetKey(de); break; } else { /* Ghost... */ continue; } } } }
Redis根据server.maxmemory_samples配置选择固定数量的key,然后比较它们的LRU访问时间,然后移除最长未被访问的key。 maxmemory_samples值越大,Redis近似LRU算法越接近严格LRU算法,但相应的消耗也会增加。因此,频繁的内存回收会降低redis的性能,主要是寻找回收节点和删除需要回收的节点的开销。
所以,一般情况下,我们在配置redis的时候,尽量不要进行这样的内存溢出回收操作。 Redis可以配置maxmemory,used_memory指的是redis实际占用的内存。但是由于操作系统还有其他软件和内存碎片以及交换区的存在,所以我们的实际内存应该大于redis中设置的maxmemory。具体大小取决于系统环境和软件环境。 maxmemory 也大于used_memory。由于碎片的存在,一般需要1~2G。 来源:cnblogs.com/niejunlei/p/12898225.html
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。