阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Redis 的数据被删除还占内存吗?

74次阅读
没有评论

共计 3414 个字符,预计需要花费 9 分钟才能阅读完成。

导读 如果你发现明明 Redis 存储数据的内存占用远小于操作系统分配给 Redis 的内存,而又无法保存数据,那可能出现大量内存碎片了。

Redis 的数据被删除还占内存吗?

操作系统分配给 Redis 的内存有 6GB,通过指标 used_memory_human 发现存储数据只使用了 4GB,为何会这样?为何无法保存数据?

通过 CONFIG SET maxmemory 100mb 或者在 redis.conf 配置文件设置 maxmemory 100mb Redis 内存占用限制。当达到内存最大值,会触发内存淘汰策略删除数据。

除此之外,当 key 达到过期时间,Redis 会有以下两种删除过期数据的策略:

后台定时任务选取部分数据删除;
惰性删除。
具体原理请移步《​​Redis 的过期数据删除那些事​​》。

假设 Redis 实例保存了 5GB 的数据,现在删除了 2GB 数据,Redis 进程占用的内存一定会降低么?(也叫做 RSS,进程消耗内存页数)。

答案是:可能依然占用了大约 5GB 的内存,即使 Redis 的数据只占用了 3GB 左右。

大家一定要设置 maxmemory,否则 Redis 会继续为新写入的数据分配内存,无法分配就会导致应用程序报错,当然不会导致宕机。

释放的内存去哪了

明明删除了数据,使用 top 命令查看,为何还是占用了那么多内存?

内存都去哪了?使用 info memory 命令获取 Redis 内存相关指标,我列举了几个重要的数据:

127.0.0.1:6379> info memory
# Memory
used_memory:1132832  // Redis 存储数据占用的内存量
used_memory_human:1.08M  // 人类可读形式返回内存总量
used_memory_rss:2977792  // 操作系统角度,进程占用的物理总内存
used_memory_rss_human:2.84M // used_memory_rss 可读性模式展示
used_memory_peak:1183808 // 内存使用的最大值,表示 used_memory 的峰值
used_memory_peak_human:1.13M  // 以可读的格式返回 used_memory_peak 的值
used_memory_lua:37888   // Lua 引擎所消耗的内存大小。used_memory_lua_human:37.00K
maxmemory:2147483648    // 能使用的最大内存值,字节为单位。maxmemory_human:2.00G  // 可读形式
maxmemory_policy:noeviction // 内存淘汰策略

// used_memory_rss / used_memory 的比值,代表内存碎片率
mem_fragmentation_ratio:2.79

Redis 进程内存消耗主要由以下部分组成:

  • Redis 自身启动所占用的内存。
  • 存储对象数据内存。
  • 缓冲区内存:主要由 client-output-buffer-limit 客户端输出缓冲区、复制积压缓冲区、AOF 缓冲区。
    内存碎片。
  • Redis 的数据被删除还占内存吗?

    Redis 自身空进程占用的内存很小可以忽略不计,对象内存是占比最大的一块,里面存储着所有的数据。

    缓冲区内存在大流量场景容易失控,造成 Redis 内存不稳定,需要重点关注。

    内存碎片过大会导致明明有空间可用,但是却无法存储数据。

    碎片 = used_memory_rss 实际使用的物理内存(RSS 值)除以 used_memory 实际存储数据内存。

    什么是内存碎片

    内存碎片会造成明明有内存空间空闲,可是却无法存储数据。举个例子,你跟漂亮小姐姐去电影院看电影,肯定想连在一块。

    假设现在有 8 个座位,已经卖出了 4 张票,还有 4 张可以买。可是好巧不巧,买票的人很奇葩,分别间隔一个座位买票。

    即使还有 4 个座位空闲,可是你却买不到两个座位连在一块的票,厚礼蟹!

    Redis 的数据被删除还占内存吗?

    内存碎片形成原因

    内存碎片是什么原因导致呢?

    主要有两个原因:

  • 内存分配器的分配策略。
  • 键值对的大小不一样和删改操作:Redis 频繁做更新操作、大量过期数据删除,释放的空间(不够连续)无法得到复用,导致碎片率上升。
  • 接下来我分别探讨实际发生的原因……

    内存分配器的分配策略

    Redis 默认的内存分配器采用 jemalloc,可选的分配器还有:glibc、tcmalloc。

    内存分配器并不能做到按需分配,而是采用固定范围的内存块进行分配。

    例如 8 字节、16 字节…..,2 KB,4KB,当申请内存最近接某个固定值的时候,jemalloc 会给它分配最接近固定值大小的空间。

    这样就会出现内存碎片,比如程序只需要 1.5 KB,内存分配器会分配 2KB 空间,那么这 0.5KB 就是碎片。

    ​这么做的目的是减少内存分配次数,比如申请 22 字节的空间保存数据,jemalloc 就会分配 32 字节,如果后边还要写入 10 字节,就不需要再向操作系统申请空间了,可以使用之前申请的 32 字节。

    删除 key 的时候,Redis 并不会立马把内存归还给操作系统,出现这个情况是因为底层内存分配器管理导致,比如大多数已经删除的 key 依然与其他有效的 key 分配在同一个内存页中。

    另外,分配器为了复用空闲的内存块,原有 5GB 的数据中删除了 2 GB 后,当再次添加数据到实例中,Redis 的 RSS 会保持稳定,不会增长太多。

    因为内存分配器基本上复用了之前删除释放出来的 2GB 内存。​

    键值对大小不一样和删改操作

    由于内存分配器是按照固定大小分配内存,所以通常分配的内存空间比实际数据占用的大小多一些,会造成碎片,降低内存的存储效率。

    另外,键值对的频繁修改和删除,导致内存空间的扩容和释放,比如原本占用 32 字节的字符串,现在修改为占用 20 字节的字符串,那么释放出的 12 字节就是空闲空间。

    如果下一个数据存储请求需要申请 13 字节的字符串,那么刚刚释放的 12 字节空间无法使用,导致碎片。

    碎片最大的问题:空间总量足够大,但是这些内存不是连续的,可能大致无法存储数据。

    内存碎片解决之道

    那该如何解决呢?

    首先要确定是否发生了内存碎片,重点关注前面 INFO memory 命令提示的 mem_fragmentation_ratio 指标,表示内存碎片率:

    mem_fragmentation_ratio = used_memory_rss/ used_memory

    如果 1

    自动清理内存碎片的代价

    自动清理虽好,可不要肆意妄为,操作系统把数据移动到新位置,再把原有空间释放是需要消耗资源的。

    Redis 操作数据的指令是单线程,所以在数据复制移动的时候,只能等待清理碎片完成才能处理请求,造成性能损耗。

    如何避免清理碎片对性能的影响又能实现自动清理呢?

    好问题,通过以下两个参数来控制内存碎片清理和结束时机,避免占用 CPU 过多,减少清理碎片对 Redis 处理请求的性能影响。

    开启自动内存碎片清理
    CONFIG SET activedefrag yes

    这只是开启自动清理,何时清理要同时满足以下两个条件才会触发清理操作。

    清理的条件

    active-defrag-ignore-bytes 200mb:内存碎片占用的内存达到 200MB,开始清理。

    active-defrag-threshold-lower 20:内存碎片的空间占比超过系统分配给 Redis 空间的 20%,开始清理。

    避免对性能造成影响

    清理时间有了,还需要控制清理对性能的影响。由一项两个设置先分配清理碎片占用的 CPU 资源,保证既能正常清理碎片,又能避免对 Redis 处理请求的性能影响。

    active-defrag-cycle-min 20:自动清理过程中,占用 CPU 时间的比例不低于 20%,从而保证能正常展开清理任务。

    active-defrag-cycle-max 50:自动清理过程占用的 CPU 时间比例不能高于 75%,超过的话就立刻停止清理,避免对 Redis 的阻塞,造成高延迟。

    总结

    如果你发现明明 Redis 存储数据的内存占用远小于操作系统分配给 Redis 的内存,而又无法保存数据,那可能出现大量内存碎片了。

    通过 info memory 命令,看下内存碎片 mem_fragmentation_ratio 指标是否正常。

    那么我们就开启自动清理并合理设置清理时机和 CPU 资源占用,该机制涉及到内存拷贝,会对 Redis 性能造成潜在风险。

    如果遇到 Redis 性能变慢,排查下是否由于清理碎片导致,如果是,那就调小 active-defrag-cycle-max 的值。

    阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

    腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

    代金券:在阿里云专用满减优惠券

    正文完
    星哥玩云-微信公众号
    post-qrcode
     0
    星锅
    版权声明:本站原创文章,由 星锅 于2024-07-24发表,共计3414字。
    转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
    【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
    阿里云-最新活动爆款每日限量供应
    评论(没有评论)
    验证码
    【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中