【死磕 Redis】—— 理解 Redis 的内存

原文出处:Java 技术驿站chenssy算法


咱们知道 Redis 的全部数据都存储在内存中,内存是咱们系统中的一个很是珍贵的资源,不能随意浪费,因此如何合理高效地利用 Redis 内存就变得很是重要了。本文从两个方面来阐述 Redis 的内存机制:数据库

  1. 知道 Redis 的内存主要消耗在什么地方
  2. 如何管理内存

查看内存

在文章[【死磕 Redis】----- info 命令详解]()介绍了 info memory 命令能够查看 Redis 内存消耗状况,是咱们分析 Redis 内存使用状况的好工具。执行命令后以下:安全

咱们重点关注几个指标:服务器

属性名 属性说明
used_memory Redis 分配器分配的内存总量,指 Redis 存储的全部数据所占的内存
used_memory_human 以可读的形式返回 user_memory
used_memory_rss Redis 进程占用的物理内存总量
used_memory_peak used_memory 使用的峰值
used_memory_peak_human 可读格式返回 used_memory_peak
used_memory_lua Lua 引擎消耗的内存大小
mem_fragmentation_ratio used_memory_rss/used_memory 比值,内存碎片率
mem_allocator Redis 所使用的内存分配器,默认 jemalloc

这里咱们须要重点关注app

mem_fragmentation_ratio > 1 说明多出来的部分名没有用于数据存储,而是被内存碎片所消耗,相差越大,说明内存碎片率越严重。 mem_fragmentation_ratio < 1 通常出如今Redis内存交换(Swap)到硬盘致使(used_memory > 可用最大内存时,Redis会把旧的和不适用的数据写入到硬盘,这块空间就叫Swap空间),出现这种状况须要格外关注,硬盘速度远远慢于内存,Redis性能就会变得不好,甚至僵死。 在理想状况下 mem_fragmentation_ratio 只会比 1 稍微大一点点,也就是 used_memory_rss 的值应该只比 used_memory 稍微高一些。运维

内存消耗划分

Redis 的内存主要包括:对象内存 + 缓冲内存 + 自身内存 + 内存碎片。以下dom

对象内存工具

对象内存是 Redis 内存中占用最大的一块,存储着全部的用户数据。咱们知道 Redis 是一个 key-value 的内存数据库,全部的数据都采用 key-value 型数据类型,每次在建立 key-value 键值对对象的时候都要建立两个对象:key 对象和value 对象。其中 key 对象是字符串,value 对象咱们知道有五中数据类型-String、Hash、List、Set、Zset,每种数据类型在使用的时候占用的内存不一样。性能

缓冲内存lua

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

  • 客户端缓冲:普通的客户端链接
  • AOF 缓冲区:Redis 持久化分为两种:RDB 和 AOF,其中 RDB 是内存快照,AOF 是将 Redis 的命令 append 在文件中,不过在写入文件以前会先写入到缓冲区,而后根据不一样的持久化策略向磁盘进行同步。在进行 AOF 重写时也有一个AOF 重写缓冲区。通常 AOF 缓冲区都会比较小。
  • 复制积压缓冲区:主要用于主从同步。在进行主从同步时,Redis 会将最新的命令写入到复制积压缓冲区,在进行复制的时候,会校验复制偏移量是否在复制积压缓冲区中,若是是则进行部分复制,不然进行全量复制。它默认状况下是 1MB,咱们须要根据实际请求适当调整他的大小,毕竟设置过小的话,可能会使部分复制退化为全量复制。

自身内存

自身内存主要指 AOF/RDB 的时候 Redis 建立子进程内存的消耗,通常这部分的消耗会比较小。

内存碎片

目前可选的分配器有 jemalloc、glibc、tcmalloc,默认 jemalloc。

出现高内存碎片问题的状况:大量的更新操做,好比 append、setrange;大量的过时键删除,释放的空间没法获得有效利用。

解决办法:数据对齐,安全重启(高可用/主从切换)。

内存管理

设置 maxmemory

若是咱们不设置 maxmemory ,Redis 则默认使用无限内存,因此为了 Redis 不系统的内存耗尽,咱们在使用 Redis 的时候尽可能去配置 maxmemory,给 Redis 设置内存使用上限。maxmemory 配置的是 Redis 的实际使用内存,即 used_memory,可是因为有内存碎片的存在,因此 Redis 实际使用的内存会比 used_memory 要大,在合理状况下通常只会大一点点。

配置内存回收策略

Redis 回收内存大体有两种机制:

  1. 删除达到过时时间的对象
  2. 当内存达到 maxmemory 时触发内存溢出控制策略,强制删除选择出来的对象

Redis 删除过时键值对对象通常有两种策略:惰性删除和主动定时任务删除。

惰性删除:这种删除策略,Redis 不会主动去删除已通过期的键值对,而是等待客户端去读取带有超时属性的键时,若是已经超时了则删除该键值对对象,而后返回空。这样有一个好处就是节省了 CPU ,由于 Redis 不须要单独去维护 TTL 链表来处理过时键的删除,可是有一个坏处就是若是过时的键一直都没有被访问,则永远不会被删除了。那么怎么解决呢?Redis 提供了一个定时任务的删除机制来补救。

定时任务删除:Redis 内部维护一个定时任务,默认是每秒运行 10 次,删除逻辑以下图:

内存溢出控制策略

当 Redis 所用内存达到 maxmemory 上限时会触发相应的溢出控制策略。Redis支持6种策略,以下所示:

策略 说明
noeviction 默认策略,不会删除任何数据,拒绝全部写入操做并返 回客户端错误信息(error)OOM command not allowed when used memory,此 时Redis只响应读操做。
volatile-lru 根据LRU算法删除设置了超时属性(expire)的键,直 到腾出足够空间为止。若是没有可删除的键对象,回退到noeviction策略。
allkeys-lru 根据LRU算法删除键,无论数据有没有设置超时属性, 直到腾出足够空间为止。
allkeys-random 随机删除全部键,直到腾出足够空间为止。
volatile-random 随机删除过时键,直到腾出足够空间为止。
volatile-ttl 根据键值对象的ttl属性,删除最近将要过时数据。若是没有,回退到noeviction策略。

内存溢出控制策略能够使用 config set maxmemory-policy {policy} 语句进行动态配置。

当 Redis 由于内存溢出删除键时,能够经过执行 info stats 命令查看 evicted_keys 指标找出当前 Redis 服务器已剔除的键数量。

参考

相关文章
相关标签/搜索