我们都知道Redis是基于内存的一个数据库,那么Redis是怎么管理内存的呢?今天这篇文章主要分享一下Redis的内存分配和简单的查看Redis内存使用情况。
Redis进程的内存消耗主要包括:自身内存 + 对象内存 + 缓冲内存 + 内存碎片。
Redis自身内存消耗非常少,通常used_memory在800KB左右,used_memory_rss在3M左右。Redis的内存消耗主要在于后面三个。(used_memory和used_memory_rss的概念在下面介绍)
对象内存是Redis内存占用最大的一块,存储着用户的所有数据,还包括慢查询日志等Redis帮我们维护的一些内存数据。
缓冲内存主要包括:客户端缓冲、复制积压缓冲、AOF重写缓冲。
客户端缓冲指的是所有连到Redis服务器的TCP连接的输入缓冲和输出缓冲。
Redis为每个客户端分配了输入缓冲区,用于临时保存客户端发过来的命令,同时Redis服务器会从输入缓冲区中拉取命令执行,输入缓冲区为客户端向服务端发送的命令提供了缓冲的功能。输入缓冲区大小无法控制,每个客户端的输入缓冲区最大空间为1G,如果超出将断开连接。
同样的Redis为每个客户端分配了输出缓冲区,用于临时保存服务端执行的命令结果,同时Redis服务器会从输出缓冲区中拉取结果返回到客户端,输出缓冲区为服务端向客户端返回结果提供了缓冲。
输出缓冲区根据客户端的类型又划分为三种:普通客户端、发布订阅客户端、从客户端(Redis复制的slave客户端)。每种客户端的输出规则也不一样,这里就不细说了。
Redis在2.8版本之后提供了一个可重用的固定大小的缓冲区用于实现增量复制的功能,根据repl-backlog-size参数来控制,默认大小1MB。
对于复制积压缓冲区主节点只有一个,所有从节点共享一个,这个缓冲区可以有效地避免全量复制。
AOF重写缓冲区用于在AOF重写期间保存写命令,所以AOF重写缓冲区的大小取决于AOF的时间以及AOF重写期间的写命令数量。
等到AOF重写完成之后,会将AOF重写缓冲区中的数据写到AOF文件,从而清空AOF重写缓冲区。
Redis默认内存分配器采用jemalloc,可选的分配器还有:glibe、tcmalloc。
内存分配器是为了更好的管理和重复利用内存,分配内存策略一般采用固定范围的内存块进行内存分配。
这里不去深究jemalloc的内存分配原理,简单地说jemalloc将内存空间划分为三个部分:Small class、Large class、Huge class,每个部分又划分为很多小的内存块单位:
- Small class: [8byte], [16byte, 32byte, … 128byte], [192byte, 256byte, … 512byte], [768byte, 1024byte, … 3840byte]
- Large class: [4kb, 8kb, 12kb, … 4072kb]
- Huge class: [4mb, 8mb, 12mb …]
简单来说就是采用不同大小的内存块来存储不同大小的内存对象,比如说一个5kb的对象就会存到8kb的内存块中,那么剩下的3kb内存就变成了内存碎片,不能再被分配给其他对象。
通常在对key做频繁更新操作和大量过期key被删除的时候会导致碎片率上升,可以考虑重启节点的方式重新整理碎片。
使用 info 命令可以看到当前Redis内存使用情况:
192.168.1.4:0>info memory
"# Memory
used_memory:1938704
used_memory_human:1.85M
used_memory_rss:10444800
used_memory_rss_human:9.96M
used_memory_peak:2948848
used_memory_peak_human:2.81M
used_memory_peak_perc:65.74%
used_memory_overhead:1919050
used_memory_startup:786608
used_memory_dataset:19654
used_memory_dataset_perc:1.71%
total_system_memory:8083607552
total_system_memory_human:7.53G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:4294967296
maxmemory_human:4.00G
maxmemory_policy:noeviction
mem_fragmentation_ratio:5.39
mem_allocator:jemalloc-4.0.3
active_defrag_running:0
lazyfree_pending_objects:0
"
其中:
属性名 | 属性说明 |
---|---|
used_memory | Redis内部存储的所有数据占用的内存 |
used_memory_human | used_memory 以M为单位显示 |
used_memory_rss | 操作系统为Redis进程分配的物理内存总量 |
used_memory_peak | 内存使用过的最大值 |
maxmemory | 给Redis分配的内存上限 |
total_system_memory | 系统内存 |
used_memory_lua | Lua脚本占用内存大小 |
需要注意的是其中 used_memory 表示Redis内部存储的所有数据占用的内存,也就是对象内存,而 used_memory_rss 表示操作系统为Redis进程分配的物理内存总量,也就是上面四种内存的总和。
当used_memory < used_memory_rss时,说明used_memory_rss中多余出来的内存没有被用来存储对象。如果两个值的差值很大,说明碎片率很高。
当used_memory > used_memory_rss时,说明操作系统采用了内存交换,把Redis内存交换(swap)到硬盘。内存交换(swap)对于Redis来说是致命的,Redis能保证高性能的一个重要前提就是读写都基于内存。如果操作系统把Redis使用的部分内存交换到硬盘,由于硬盘的读写效率比内存低上百倍,会导致Redis性能急剧下降,特别容易引起Redis阻塞。
今天这篇文章主要介绍了Redis的内存划分以及查看Redis的内存使用情况,后面将带来Redis的内存上限设置以及Redis的回收策略。