Redis 内存消耗及回收

news2024/11/30 10:33:58

Redis 是一个开源、高性能的 Key-Value 数据库,被广泛应用在服务器各种场景中。Redis 是一种内存数据库,将数据保存在内存中,读写效率要比传统的将数据保存在磁盘上的数据库要快很多。所以,监控 Redis 的内存消耗并了解 Redis 内存模型对高效并长期稳定使用 Redis 至关重要。

在介绍之前先说明下,一般生产环境下,对开发同事不会开放直连 redis 集群的权限,一般是提供 daas 平台,通过可视化命令窗口,输入 redis 命令,一般只有 read 权限;对于 write 操作,需要提 redis 数据变更单,而对于 redis 内存、大 key、慢命令,一般都会将信息集成及中显示在监控看板,而不需要开发同事自己去输入命令;但是基本的相关知识还是要具备的。

reids 内存分析

redis 内存使用情况:info memory

示例:可以看到,当前节点内存碎片率为 226893824/209522728 ≈ 1.08,使用的内存分配器是 jemalloc。

used_memory_rss 通常情况下是大于 used_memory 的,因为内存碎片的存在。

但是当操作系统把 redis 内存 swap 到硬盘时,memory_fragmentation_ratio 会小于 1。redis 使用硬盘作为内存,因为硬盘的速度,redis 性能会受到极大的影响。

redis 内存使用

redis 的内存使用分布:自身内存,键值对象占用、缓冲区内存占用及内存碎片占用。

redis 空进程自身消耗非常的少,可以忽略不计,优化内存可以不考虑此处的因素。

对象内存

对象内存,也即真实存储的数据所占用的内存。

redis k-v 结构存储,对象占用可以简单的理解为 k-size + v-size。

redis 的键统一都为字符串类型,值包含多种类型:string、list、hash、set、zset五种基本类型及基于 string 的 Bitmaps 和 HyperLogLog 类型等。

在实际的应用中,一定要做好 kv 的构建形式及内存使用预期,。

缓冲内存

缓冲内存包括三部分:客户端缓存、复制积压缓存及 AOF 缓冲区。

客户端缓存

接入redis服务器的TCP连接输入输出缓冲内存占用,TCP 输入缓冲占用是不受控制的,最大允许空间为 1G。输出缓冲占用可以通过 client-output-buffer-limit 参数配置。

redis 客户端主要分为从客户端、订阅客户端和普通客户端。

  • 从客户端连接占用

也就是我们所说的 slave,主节点会为每一个从节点建立一条连接用于命令复制,缓冲配置为:client-output-buffer-limit slave 256mb 64mb 60。

主从之间的间络延迟及挂载的从节点数量是影响内存占用的主要因素。因此在涉及需要异地部署主从时要特别注意,另外,也要避免主节点上挂载过多的从节点(<=2);

  • 订阅客户端内存占用

发布订阅功能连接客户端使用单独的缓冲区,默认配置:client-output-buffer-limit pubsub 32mb 8mb 60。

当消费慢于生产时会造成缓冲区积压,因此需要特别注意消费者角色配比及生产、消费速度的监控。

  • 普通客户端内存占用

除了上述之外的其它客户端,如我们通常的应用连接,默认配置:client-output-buffer-limit normal 1000。

可以看到,普通客户端没有配置缓冲区限制,通常一般的客户端内存消耗也可以忽略不计。

但是当 redis 服务器响应较慢时,容易造成大量的慢连接,主要表现为连接数的突增,如果不能及时处理,此时会严重影响 redis 服务节点的服务及恢复。

关于此,在实际应用中需要注意几点:

  • maxclients 最大连接数配置必不可少。

  • 合理预估单次操作数据量(写或读)及网络时延 ttl。

  • 禁止线上大吞吐量命令操作,如 keys 等。

高并发应用情景下,redis内存使用需要有实时的监控预警机制。

复制积压缓冲区

v2.8 之后提供的一个可重用的固定大小缓冲区,用以实现向从节点的部分复制功能,避免全量复制。配置单数:repl-backlog-size,默认 1M。单个主节点配置一个复制积压缓冲区。

AOF缓冲区

AOF重写期间增量的写入命令保存,此部分缓存占用大小取决于 AOF 重写时间及增量。

内存碎片内存占用

固定范围内存块儿分配。redis默认使用jemalloc内存分配器,其它包括glibc、tcmalloc。

内存分配器会首先将可管理的内存分配为规定不同大小的内存块以备不同的数据存储需求,但是,我们知道实际应用中需要存储的数据大小不一,规范不一,内存分配器只能选择最接近数据需求大小的内存块儿进行分配,这样就伴随着“占不满”空间的碎片浪费。

jemalloc针对内存碎片有相应的优化策略,正常碎片率为mem_fragmentation_ratio在1.03左右。

第二部分我们说过,对string值得频繁append及range操作会会导致内存碎片问题,另外,第七部分,SDS惰性内存回收也会导致内存碎片,同时过期键内存回收也伴随着所释放空间的无法充分利用,导致内存碎片率上升的问题。

碎片处理:

  • 应用层面:尽量避免差异化的键值使用,做好数据对齐。

  • redis服务层面:可以通过重启服务,进行碎片整理。

maxmemory 及 maxmemory-policy

redis 基于以上配置控制 redis 最大可用内存及内存回收。需要注意的是内存回收执行影响redis的性能,避免频繁的内存回收开销。

redis 子进程内存消耗

子进程即 redis 执行持久化(RDB/AOF)时 fork 的子任务进程。

关于 linux 系统的写时复制机制

父子进程会共享相同的物理内存页,父进程处理写请求时会对需要修改的页复制一份副本进行修改,子进程读取的内存则为fork时的父进程内存快照,因此,子进程的内存消耗由期间的写操作增量决定。

关于 linux 的透明大页机制THP(Transparent Huge Page)

THP 机制会降低 fork 子进程的速度:写时复制内存页由 4KB 增大至 2M。高并发情境下,写时复制内存占用消耗影响会很大,因此需要选择性关闭。

关于linux配置

一般需要配置 linux 系统 vm.overcommit_memory = 1,以允许系统可以分配所有的物理内存。防止fork任务因内存而失败。

redis 内存管理

redis 的内存管理主要分为两方面:内存上限控制及内存回收管理。

内存上限:maxmemory

目的:缓存应用内存回收机制触发 + 防止物理内存用尽(redis 默认无限使用服务器内存) + 服务节点内存隔离(单服务器上部署多个 redis 服务节点)

在进行内存分配及限制时要充分考虑内存碎片占用影响。动态调整,扩展redis服务节点可用内存:config set maxmemory {}

内存回收

回收时机:键过期、内存占用达到上限

过期键删除

redis 键过期时间保存在内部的过期字典中,redis 采用惰性删除机制+定时任务删除机制。

  • 惰性删除

即读时删除,读取带有超时属性的键时,如果键已过期,则删除然后返回空值。这种方式存在问题是,触发时机,加入过期键长时间未被读取,那么它将会一直存在内存中,造成内存泄漏。

  • 定时任务删除

redis 内部维护了一个定时任务(默认每秒10次,可配置),通过自适应法进行删除。

删除逻辑如下:

需要说明的一点是,快慢模式执行的删除逻辑相同,这是超时时间不同。

内存溢出控制

当内存达到 maxmemory,会触发内存回收策略,具体策略依据 maxmemory-policy 来执行。

  • noevication:默认不回收,达到内存上限,则不再接受写操作,并返回错误。

  • volatile-lru:根据LRU算法删除设置了过期时间的键,如果没有则不执行回收。

  • allkeys-lru:根据LRU算法删除键,针对所有键。

  • allkeys-random:随机删除键。

  • volatitle-random:随机删除设置了过期时间的键。

  • volatilte-ttl:根据键ttl,删除最近过期的键,同样如果没有设置过期的键,则不执行删除。

动态配置:config set maxmemory-policy {}

在设置了maxmemory情况下,每次的redis操作都会检查执行内存回收,因此对于线上环境,要确保所这只的 maxmemory > used_memory。

另外,可以通过动态配置 maxmemory 来主动触发内存回收

内存回收策略

内存回收触发有两种情况,也就是内存使用达到maxmemory上限时候触发的溢出回收,还有一种是我们设置了过期的对象到期的时候触发的到期释放的内存回收。

Redis内存使用达到maxmemory上限时候触发的溢出回收;Redis 提供了几种策略 (maxmemory-policy) 来让用户自己决定该如何腾出新的空间以继续提供读写服务:

  • (1)volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  • (2)volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  • (3)volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  • (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:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key

redis默认的策略就是noeviction策略,如果想要配置的话,需要在配置文件中写这个配置:

maxmemory-policy volatile-lru

Redis 的 LRU 算法

LRU是Least Recently Used 近期最少使用算法,很多缓存策略都使用了这种策略进行空间的释放,在学习操作系统的内存回收的时候也用到了这种机制进行内存的回收,类似的还有LFU(Least Frequently Used)最不经常使用算法,这种算法。

我们在上面的描述中也可以了解到,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真实占用的内存,但是由于操作系统还有其他软件以及内存碎片还有swap区的存在,所以我们实际的内存应该比redis里面设置的maxmemory要大,具体大多少视系统环境和软件环境来定。maxmemory也要比used_memory大,一般由于碎片的存在需要做1~2个G的富裕。

链接:https://blog.csdn.net/minghao0508/article/details/124143905

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/527849.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tinyWebServer 学习笔记——四、日志系统

文章目录 一、基础知识1. 概念2. API 二、代码解析1. 单例模式2. 阻塞队列3. 日志类定义4. 生成日志文件并判断写入方式5. 日志分级与分文件 参考文献 一、基础知识 1. 概念 流程图 [2] 日志&#xff1a;由服务器自动创建&#xff0c;用于记录运行状态和错误信息&#xff1b;同…

C++系列六:运算符

C运算符 1. 算术运算符2. 关系运算符3. 逻辑运算符4. 按位运算符5. 取地址运算符6. 取内容运算符7. 成员选择符8. 作用域运算符9. 总结 1. 算术运算符 算术运算符用于执行基本数学运算&#xff0c;例如加减乘除和取模等操作。下表列出了C中支持的算术运算符&#xff1a; 运算…

JSON+AJAX+ThreadLocal+文件上传下载

文章目录 JSON和AJAX文档介绍1. JSON介绍1.1 JSON快速入门1.2 JSON和字符串转换1.2.1 JSON转字符串1.2.2 字符串转JSON1.2.3 JSON和字符串转换细节 1.3 JSON在java中使用1.3.1 Java对象和JSON字符串转换1.3.2 List对象和JSON字符串转换1.3.3 Map对象和JSON字符串转换 2. Ajax介…

DAY 58 数据库的存储引擎

存储引擎的概念 什么是存储引擎 MySQL中的数据用各种不下同的技术存储在文件中&#xff0c;每一种技术都使用不同的存储机制、索引技巧、锁定水平并最终提供不同的功能和能力&#xff0c;这些不同的技术以及配套的功能在MySQL中称为存储引擎。 存储引擎是MySQL将数据存储在文…

JUC之volatile

作用&#xff1a;volatile是Java提供的一种轻量级的同步机制 保证内存可见性 不保证原子性 防止指令重排序 public class VolatileDemo {private static int num0;public static void main(String[] args) {new Thread(()->{while (num0){}},"A").start();try {…

Spark大数据处理讲课笔记4.6 Spark SQL数据源 - JDBC

文章目录 零、本讲学习目标一、Spark SQL读取关系数据库二、Spark SQL JDBC连接属性三、创建数据库与表&#xff08;一&#xff09;创建数据库&#xff08;二&#xff09;创建学生表&#xff08;二&#xff09;创建成绩表 四、读取和写入数据库表&#xff08;一&#xff09;利用…

力扣第 104 场双周赛 2681. 英雄的力量

原题链接力扣 题目大意&#xff1a;我开始看成连续子段了&#xff0c;写了个递归程序....... 一个数组任选一个子序列&#xff0c;子序列的力量值最大值平方*最小值。求所有子序列的力量和。 分析过程&#xff1a;如序列长度为n&#xff0c;子序列总数为2的n次幂&#xff0c…

SpringCloud------zookeeper代替Eureka,zookeeper版本冲突解决(七)

SpringCloud------zookeeper代替Eureka&#xff08;七&#xff09; SpringCloud整合zookeeper代替Eureka 注册中心zookeeper zookeeper是一个分布式协调工具&#xff0c;可以实现注册中心功能 关闭Linux服务器防火墙后&#xff0c;启动zookeeper服务器 zookeeper服务器取代Eur…

mac桌面文件删除怎么恢复?别急,有办法!

大家是不是习惯于将临时要用的文件都存放在桌面上。虽然文件放在桌面上&#xff0c;可以方便我们随时调取&#xff0c;但是也容易出现误删除的情况&#xff0c;给我们带来麻烦。mac桌面文件删除怎么恢复&#xff1f;希望通过本篇教程&#xff0c;你能找回误删除的桌面文件。 案…

script标签type值application/json,importmap和module

type&#xff08;默认text/javascript&#xff09; 该属性定义 script 元素包含或src引用的脚本语言。属性的值为 MIME 类型&#xff08;媒体类型&#xff09;&#xff1b; 如果没有定义这个属性&#xff0c;脚本会被视作 JavaScript。 如果 MIME 类型不是 JavaScript 类型&a…

GPT4结对编程实战,鹅厂一线研发真实使用感受

&#x1f449;腾小云导读 ChatGPT4相比ChatGPT3.5在逻辑推理能力上有很大的进步&#xff0c;其代码生成能力颇为优越。因此作者尝试在工作中某些不涉密的基础工作上&#xff0c;应用ChatGPT4来提升研发效率&#xff0c;简单尝试之后发现其在不少场景是有效的。本文将向大家展示…

元宇宙又“死”了!Epic老板:你当6亿用户是摆设?

“扎克伯格花了数年时间试图让Metaverse成为现实&#xff0c;但现在它已被AI取代&#xff0c;并走向科技创意的坟墓。”一篇表达“元宇宙已死”的文章近期在推特上引发热议&#xff0c;而游戏制作公司Epic Games CEO Tim Sweeney的还击更是让这个话题热上加热。 “搞一次在线守…

【SSL证书】使用mkcert创建局域网或单机可信任Windows格式证书

初学者对SSL证书的理解可能非常模糊。所谓SSL证书&#xff0c;其实它包含两个方面&#xff0c;一是根证书&#xff0c;二是HTTPS的证书&#xff0c;HTTPS证书合法性由其根证书来进行认定。几大证书供应商的根证书一般都预置在系统中了&#xff0c;所以给人的错觉就是只知HTTPS证…

深入解析 Facebook 分析工具,洞察用户行为和优化策略

作为一名 Facebook 运营者&#xff0c;了解用户行为和优化策略是至关重要的。在本文中&#xff0c;我们将深入解析Facebook 分析工具&#xff0c;帮助你更好地洞察用户行为和优化策略。 1.Facebook 像素 Facebook 像素是一个重要的工具&#xff0c;可以帮助运营者了解用户在网…

SNMP简介

背景 简单网络管理协议SNMP&#xff08;Simple Network Management Protocol&#xff09;用于网络设备的管理。网络设备种类多种多样&#xff0c;不同设备厂商提供的管理接口&#xff08;如命令行接口&#xff09;各不相同&#xff0c;这使得网络管理变得愈发复杂。为解决这一…

新车推迟、裁员降本,沃尔沃被现实狠狠“扇了一个耳光”

汽车行业的魅力&#xff0c;或许就在于不断的给自己打气&#xff0c;然后被打脸。 今年&#xff0c;上海车展开幕前&#xff0c;沃尔沃汽车大中华区销售公司总裁钦培吉在新车发布会上直言&#xff1a;“新势力会的&#xff0c;我们三年就学会了&#xff1b;我们会的&#xff0c…

无影云桌面,搭建一个属于自己的云上主机

无影云桌面&#xff0c;搭建一个属于自己的云上主机 1.无影云桌面介绍2.无影云桌面试用3.无影云桌面尝鲜4.测试云桌面的连通性5.体验无影云的娱乐办公场景6.将无影云桌面作为服务器使用7.无影云桌面使用总结 1.无影云桌面介绍 无影云桌面是一种云计算技术&#xff0c;可以将用…

《LKD3粗读笔记》(12)内存管理

1、页 内核把物理页作为内存管理的基本单元内存管理单元&#xff08;MMU&#xff09;以页为单位来管理系统中的页表从虚拟内存的角度看&#xff0c;页就是最小单位。体系结构不同&#xff0c;支持页的大小也不尽相同。大多数32位体系结构支持4KB的页&#xff0c;而64位体系结构…

排序算法之堆排序的实现

一、堆的相关概念 堆一般指的是二叉堆&#xff0c;顾名思义&#xff0c;二叉堆是完全二叉树或者近似完全二叉树 1. 堆的性质 ① 是一棵完全二叉树 ② 每个节点的值都大于或等于其子节点的值&#xff0c;为最大堆&#xff1b;反之为最小堆。 2. 堆的存储 一般用数组来表示堆&…

网站域名查询地址-域名所有者查询

域名查询注册信息查询 147SEO域名查询是一款全能的域名查询注册信息查询软件。它不仅提供了单个域名的实时查询功能&#xff0c;还支持批量域名查询功能&#xff0c;可以快速查询多个域名的注册和到期信息。以下是147SEO域名查询的主要特点&#xff1a; 批量域名查询&#xff…