前言

redis 是一个内存型数据库,那么就需要重点关注一下内存了。

正文

理解Redis内存,首先需要掌握Redis内存消耗在哪些方面。有些内存消 耗是必不可少的,而有些可以通过参数调整和合理使用来规避内存浪费。

内存消耗可以分为进程自身消耗和子进程消耗。

首先需要了解Redis自身使用内存的统计数据,可通过执行info memory 命令获取内存相关指标。

需要重点关注的指标有:used_memory_rss和used_memory以及它们的比 值mem_fragmentation_ratio。

当mem_fragmentation_ratio>1时,说明used_memory_rss-used_memory多出 的部分内存并没有用于数据存储,而是被内存碎片所消耗,如果两者相差很大,说明碎片率严重。

当mem_fragmentation_ratio<1时,这种情况一般出现在操作系统把Redis 内存交换(Swap)到硬盘导致,出现这种情况时要格外关注,由于硬盘速 度远远慢于内存,Redis性能会变得很差,甚至僵死。

内存消耗

内存消耗划分

Redis进程内消耗主要包括:自身内存+对象内存+缓冲内存+内存碎片, 其中Redis空进程自身内存消耗非常少,通常used_memory_rss在3MB左右, used_memory在800KB左右,一个空的Redis进程消耗内存可以忽略不计。

对象内存是Redis内存占用最大的一块,存储着用户所有的数据。Redis 所有的数据都采用key-value数据类型,每次创建键值对时,至少创建两个类 型对象:key对象和value对象。对象内存消耗可以简单理解为sizeof(keys) +sizeof(values)。键对象都是字符串,在使用Redis时很容易忽略键对内存 消耗的影响,应当避免使用过长的键。value对象更复杂些,主要包含5种基本数据类型:字符串、列表、哈希、集合、有序集合。

缓冲内存

缓冲内存主要包括:客户端缓冲、复制积压缓冲区、AOF缓冲区。

客户端缓冲指的是所有接入到Redis服务器TCP连接的输入输出缓冲。 输入缓冲无法控制,最大空间为1G,如果超过将断开连接。

普通客户端:

除了复制和订阅的客户端之外的所有连接,Redis的默认 配置是:client-output-buffer-limit normal000,Redis并没有对普通客户端的输 出缓冲区做限制,一般普通客户端的内存消耗可以忽略不计,但是当有大量 慢连接客户端接入时这部分内存消耗就不能忽略了,可以设置maxclients做 限制。特别是当使用大量数据输出的命令且数据无法及时推送给客户端时, 如monitor命令,容易造成Redis服务器内存突然飙升。

从客户端:

主节点会为每个从节点单独建立一条连接用于命令复制, 默认配置是:client-output-buffer-limit slave256mb64mb60。当主从节点之间 网络延迟较高或主节点挂载大量从节点时这部分内存消耗将占用很大一部 分,建议主节点挂载的从节点不要多于2个,主从节点不要部署在较差的网 络环境下,如异地跨机房环境,防止复制客户端连接缓慢造成溢出。

订阅客户端:

订阅客户端:当使用发布订阅功能时,连接客户端使用单独的输出缓 冲区,默认配置为:client-output-buffer-limit pubsub32mb8mb60,当订阅服务 的消息生产快于消费速度时,输出缓冲区会产生积压造成输出缓冲区空间溢 出

复制积压缓冲区:Redis在2.8版本之后提供了一个可重用的固定大小缓 冲区用于实现部分复制功能,根据repl-backlog-size参数控制,默认1MB。对 于复制积压缓冲区整个主节点只有一个,所有的从节点共享此缓冲区,因此 可以设置较大的缓冲区空间,如100MB,这部分内存投入是有价值的,可以 有效避免全量复制

AOF缓冲区:这部分空间用于在Redis重写期间保存最近的写入命令。AOF缓冲区空间消耗用户无法控制,消耗的内存取决于 AOF重写时间和写入命令量,这部分空间占用通常很小。

内存碎片

Redis默认的内存分配器采用jemalloc,可选的分配器还有:glibc、 tcmalloc。内存分配器为了更好地管理和重复利用内存,分配内存策略一般 采用固定范围的内存块进行分配。例如jemalloc在64位系统中将内存空间划 分为:小、大、巨大三个范围。每个范围内又划分为多个小的内存块单位, 如下所示:

比如当保存5KB对象时jemalloc可能会采用8KB的块存储,而剩下的3KB 空间变为了内存碎片不能再分配给其他对象存储。内存碎片问题虽然是所有 内存服务的通病,但是jemalloc针对碎片化问题专门做了优化,一般不会存 在过度碎片化的问题,正常的碎片率(mem_fragmentation_ratio)在1.03左 右。但是当存储的数据长短差异较大时,以下场景容易出现高内存碎片问题:

  1. ·频繁做更新操作,例如频繁对已存在的键执行append、setrange等更新 操作。

  2. ·大量过期键删除,键对象过期删除后,释放的空间无法得到充分利 用,导致碎片率上升。、

解决手法:

  1. ·数据对齐:在条件允许的情况下尽量做数据对齐,比如数据尽量采用 数字类型或者固定长度字符串等,但是这要视具体的业务而定,有些场景无 法做到

  2. ·安全重启:重启节点可以做到内存碎片重新整理,因此可以利用高可用架构,如Sentinel或Cluster,将碎片率过高的主节点转换为从节点,进行 安全重启。

内存回收策略

Redis的内存回收机制主要体现在以下两个方面:

  1. 删除到达过期时间的键对象。

Redis所有的键都可以设置过期属性,内部保存在过期字典中。由于进 程内保存大量的键,维护每个键精准的过期删除机制会导致消耗大量的 CPU,对于单线程的Redis来说成本过高,因此Redis采用惰性删除和定时任 务删除机制实现过期键的内存回收。

a. 惰性删除

惰性删除用于当客户端读取带有超时属性的键时,如果已 经超过键设置的过期时间,会执行删除操作并返回空,这种策略是出于节省 CPU成本考虑,不需要单独维护TTL链表来处理过期键的删除。但是单独用 这种方式存在内存泄露的问题,当过期键一直没有访问将无法得到及时删 除,从而导致内存不能及时释放。正因为如此,Redis还提供另一种定时任 务删除机制作为惰性删除的补充。

b. 定时任务删除

Redis内部维护一个定时任务,默认每秒运行10次(通 过配置hz控制)。定时任务中删除过期键逻辑采用了自适应算法,根据键的 过期比例、使用快慢两种速率模式回收键

1)定时任务在每个数据库空间随机检查20个键,当发现过期时删除对 应的键。

2)如果超过检查数25%的键过期,循环执行回收逻辑直到不足25%或 运行超时为止,慢模式下超时时间为25毫秒。

3)如果之前回收键逻辑超时,则在Redis触发内部事件之前再次以快模 式运行回收过期键任务,快模式下超时时间为1毫秒且2秒内只能运行1次。

4)快慢两种模式内部删除逻辑相同,只是执行的超时时间不同。

  1. 内存使用达到maxmemory上限时触发内存溢出控制策略。

内存溢出控制策略

当Redis所用内存达到maxmemory上限时会触发相应的溢出控制策略。 具体策略受maxmemory-policy参数控制,Redis支持6种策略,如下所示:

1)noeviction:默认策略,不会删除任何数据,拒绝所有写入操作并返 回客户端错误信息(error)OOM command not allowed when used memory,此 时Redis只响应读操作。

2)volatile-lru:根据LRU算法删除设置了超时属性(expire)的键,直 到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略。

3)allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性, 直到腾出足够空间为止。

4)allkeys-random:随机删除所有键,直到腾出足够空间为止。

5)volatile-random:随机删除过期键,直到腾出足够空间为止。

6)volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据。如果 没有,回退到noeviction策略。

内存溢出控制策略可以采用config set maxmemory-policy{policy}动态配 置。Redis支持丰富的内存溢出应对策略,可以根据实际需求灵活定制,比如当设置volatile-lru策略时,

保证具有过期属性的键可以根据LRU剔除,而 未设置超时的键可以永久保留。还可以采用allkeys-lru策略把Redis变为纯缓 存服务器使用。当Redis因为内存溢出删除键时,可以通过执行info stats命令 查看evicted_keys指标找出当前Redis服务器已剔除的键数量。

每次Redis执行命令时如果设置了maxmemory参数,都会尝试执行回收 内存操作。当Redis一直工作在内存溢出(used_memory>maxmemory)的状 态下且设置非noeviction策略时,会频繁地触发回收内存的操作,影响Redis 服务器的性能。回收内存逻辑伪代码如下:

对于需要收缩Redis内存的场景,可以通过调小maxmemory来实现快速 回收。比如对一个实际占用6GB内存的进程设置maxmemory=4GB,之后第一 次执行命令时,如果使用非noeviction策略,它会一次性回收到maxmemory指定的内存量,从而达到快速回收内存的目的。注意,此操作会导致数据丢失 和短暂的阻塞问题,一般在缓存场景下使用。

下一节内存的优化。

redis 简单整理——内存的管理[二十六]的更多相关文章

  1. Web 前端开发人员和设计师必读精华文章【系列二十六】

    <Web 前端开发精华文章推荐>2014年第5期(总第26期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  2. VMware vSphere 服务器虚拟化之二十六 桌面虚拟化之View Persona Management

    VMware vSphere 服务器虚拟化之二十六 桌面虚拟化之View Persona Management 实验失败告终,启动VMware View Persona Management服务报10 ...

  3. 二十六个月Android学习工作总结【转】

    原文:二十六个月Android学习工作总结 1.客户端的功能逻辑不难,UI界面也不难,但写UI花的时间是写功能逻辑的两倍.     2.写代码前的思考过程非常重要,即使在简单的功能,也需要在本子上把该 ...

  4. 二十六、Jcreator使用初步

    摘自http://blog.csdn.net/liujun13579/article/details/7751464 二十六.Jcreator使用初步 Jcreator是一个小巧灵活的Java开发工具 ...

  5. WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[实现篇]

    原文:WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[实现篇] 元数据的导出就是实现从ServiceEndpoint对象向MetadataSet对象转换的过程,在WCF元数据框 ...

  6. 第一百二十六节,JavaScript,XPath操作xml节点

    第一百二十六节,JavaScript,XPath操作xml节点 学习要点: 1.IE中的XPath 2.W3C中的XPath 3.XPath跨浏览器兼容 XPath是一种节点查找手段,对比之前使用标准 ...

  7. mysql进阶(二十六)MySQL 索引类型(初学者必看)

    mysql进阶(二十六)MySQL 索引类型(初学者必看)   索引是快速搜索的关键.MySQL 索引的建立对于 MySQL 的高效运行是很重要的.下面介绍几种常见的 MySQL 索引类型.   在数 ...

  8. FreeSql (二十六)贪婪加载 Include、IncludeMany、Dto、ToList

    贪婪加载顾名思议就是把所有要加载的东西一次性读取. 本节内容为了配合[延时加载]而诞生,贪婪加载和他本该在一起介绍,开发项目的过程中应该双管齐下,才能写出高质量的程序. Dto 映射查询 Select ...

  9. 使用Typescript重构axios(二十六)——添加HTTP授权auth属性

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  10. 深度学习(二十六)Network In Network学习笔记

    深度学习(二十六)Network In Network学习笔记 Network In Network学习笔记 原文地址:http://blog.csdn.net/hjimce/article/deta ...

随机推荐

  1. Visual Studio部署C++环境下OpenCV库

      本文介绍在Visual Studio 2022中配置.编译C++计算机视觉库OpenCV的方法. 1 OpenCV库配置   首先,我们进行OpenCV库的下载与安装.作为一个开源的库,我们直接在 ...

  2. Sermant运行流程学习笔记,速来抄作业

    本文分享自华为云社区<Sermant 的整体流程学习梳理>,作者:用友汽车信息科技(上海)有限公司 刘亚洲 Java研发工程师. 一.sermant架构 Sermant整体架构包括Serm ...

  3. sql99等值&&非等值查询

    1 #二.sql99语法 2 /* 3 语法 4 SELECT 查询列表 5 FROM 表1 别名 [连接类型] 6 JOIN 表2 别名 7 on 连接条件 8 [where 筛选条件] 9 [gr ...

  4. node开发命令行脚本 / commander

    1. 脚本第一行添加 #!/usr/bin/env node // index.js #!/usr/bin/env node console.log('hello world') 2. package ...

  5. vscode vue 鼠标Ctrl+单击 函数跳转 插件名称:vue-helper

  6. etcd每个节点都存储了完整的键值对数据集,为什么扩容etcd集群仍可分散存储压力?

    etcd每个节点都存储了完整的键值对数据集,这主要是为了确保数据的一致性和高可用性.在这种设计下,任何一个节点都可以处理读取请求,并在本地提供数据,从而无需跨节点通信.这种冗余的数据存储方式也增加了系 ...

  7. 35_音视频播放器_seek&暂停

    目录 一.实现seek功能 二.解决点击seek操作时会出现画面快速闪过 三.实现暂停功能 3.1.音频暂停 3.2.视频暂停 一.实现seek功能 我们主要是使用ffmpeg的av_seek_fra ...

  8. 记录--用Echarts打造自己的天气预报!

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 最近刚刚学习了Echarts的使用,于是想做一个小案例来巩固一下.项目效果如下图所示: 话不多说,开始进入实战. 创建项目 这里我们 ...

  9. 基于电脑软件的任意波形发生器SIG852初识(类似虚拟示波器)

    基于电脑软件的任意波形发生器SIG852初识(类似虚拟示波器) 对于从事电路板开发的硬件工程师来说,信号源是经常使用也非常熟悉的.我们用它来作为电路板的输入,测试电路板是否能按预期正常处理这些信号.最 ...

  10. 感悟:FPGA的并行处理与PC的多线程处理

    前言 FPGA的并行设计是其高速处理的核心之一, 通过并行地处理大量的数据实现预期的功能; PC的多线程设计则是处理大量的内容而衍生出的一种处理方式, 其本质是利用CPU的高速处理能力, 将单个线程以 ...