Redis 所有数据都存在内存中,所以高效利用 Redis 内存至关重要
使用以下命令查看内存相关指标:
info memory
used_memory:存储数据所占用的内存总量
used_memory_human:人类可读的used_memory
used_memory_rss:Redis进程占用的物理内存总量
used_memory_peak:内存使用的最大值,used_memory的峰值
used_memory_peak_human:人类可读的used_memory_peak
used_memory_lua:lua引擎所占用的内存大小
mem_fragmentation_ratio:内存碎片率
mem_allocator:Redis使用的内存分配器,默认是jemalloc
自身内存 + 对象内存 + 缓冲内存 + 内存碎片,其中自身内存消耗很少。
对象内存是 Redis 内存中占用最大一块,存储着所有的用户的数据。Redis 所有的数据都采用的是 key-value 型数据类型,每次创建键值对的时候,都要创建两个对象,key 对象和 value 对象。key 对象都是字符串,value 对象的存储方式,五种数据类型 String、List、Hash、Set、Zset。每种存储方式在使用的时候长度、数据类型不同,则占用的内存就不同。
主要包括:客户端缓冲、复制积压缓冲区、AOF缓冲区
客户端缓冲:
客户端缓冲指的是所有接入到 Redis 服务器 TCP 连接的输入输出缓冲。输入缓冲无法控制,最大为1G;输出缓冲通过 client-output-buffer-limit
参数进行控制
复制积压缓冲:2.8版本之后提供的可重用的固定大小缓冲区用于实现部分复制功能,默认1MB,可通过 repl-backlog-size
参数进行控制,主要是在主从同步时用到
AOF缓冲区:AOF 持久化用的,会先写入到缓冲区,然后根据响应的策略向磁盘进行同步,消耗的内存取决于写入的命令量和重写时间,通常很小
类似于内部碎片,分配出去的内存没有被充分利用,多出来的那一部分。
出现高内存碎片问题的情况:大量的更新操作,比如append、setrange;大量的过期键删除,释放的空间无法得到有效利用
解决办法:数据对齐,安全重启(高可用/主从切换)
AOF / RDB 重写时 fork 出的子进程会占用内存
Redis默认是无限使用内存。所以在使用的时候尽量的去配置
maxmemory
使用 maxmemory
配置参数设置内存上限
config set maxmemory bytes
key 的过期属性(若设置过)保存在过期字典中,维护每个 key 精准的过期删除机制会导致消耗大量 CPU,因此 Redis 采用惰性删除和定时任务删除机制实现过期 key 的内存回收。
在客户端读取带有超时属性的键时,如果已经超过键值设置的过期时间,则删除并返回空,存在内存泄漏问题。
Redis内部维护了一个定时任务,默认是每秒运行10次,采用自适应算法,根据 key 的过期比例、使用快慢两种速率模式回收 key,流程如下:
Redis 所用内存达到 maxmemory
上限时会触发相应的溢出控制策略,由 maxmemory-policy
配置文件参数控制:
Redis 存储的所有 value 对象在内部定义为 redisObject 结构体
typedef struct redisObject { unsigned type:4; //保存信息的类型 unsigned encoding:4;//保存信息的编码方式 unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */ int refcount;//引用次数 void *ptr;//保存的指针 } robj
缩减 key 和 value 的长度:
Redis 内部维护一个[0-9999]的整数对象池,可以复用,节约内存。
注意:当开启 maxmemory
和 LRU 淘汰策略后,Redis 禁止使用共享对象池