Redis作为内存数据库,在内存中存储的内容主要是数据(键值对)除了数 据以外,Redis的其他部分也会占⽤内存。




redis 内存估算 redis内存分析_redis存储对象

redis存储示意图



数据内存

作为数据库,数据是最主要的部分;这部分占⽤的内存会统计在used_memory中。 Redis使⽤键值对存储数据,其中的值(对象)包括5种类型,即字符串、哈希、列表、集合、有序集 合。这5种类型是Redis对外提供的,实际上,在Redis内部,每种类型可能有2种或更多的内部编码实 现;此外,Redis在存储对象时,并不是直接将数据扔进内存,⽽是会对对象进⾏各种包装:如 redisObject、SDS等。

进程内存

Redis主进程本身运⾏肯定需要占⽤内存,如代码、常量池等等;这部分内存⼤约⼏兆,在⼤多数⽣产环 境中与Redis数据占⽤的内存相⽐可以忽略。这部分内存不是由jemalloc分配,因此不会统计在 used_memory中。

注意:除了主进程外,Redis创建的⼦进程运⾏也会占⽤内存,如Redis执⾏AOF、RDB重写时 创建的⼦进程。当然,这部分内存不属于Redis进程,也不会统计在used_memory和 used_memory_rss中。

缓冲内存

缓冲内存包括客户端缓冲区、复制积压缓冲区、AOF缓冲区等;其中,客户端缓冲存储客户端连接的输 ⼊输出缓冲;复制积压缓冲⽤于部分复制功能;AOF缓冲区⽤于在进⾏AOF重写时,保存最近的写⼊命 令。在了解相应功能之前,不需要知道这些缓冲的细节;这部分内存由jemalloc分配,因此会统计在 used_memory中。

内存碎⽚

内存碎⽚是Redis在分配、回收物理内存过程中产⽣的。例如,如果对数据的更改频繁,⽽且数据之间的 ⼤⼩相差很⼤,可能导致redis释放的空间在物理内存中并没有释放,但redis⼜⽆法有效利⽤,这就形成 了内存碎⽚。内存碎⽚不会统计在used_memory中。 内存碎⽚的产⽣与对数据进⾏的操作、数据的特点等都有关;此外,与使⽤的内存分配器也有关系:如 果内存分配器设计合理,可以尽可能的减少内存碎⽚的产⽣。后⾯将要说到的jemalloc便在控制内存碎 ⽚⽅⾯做的很好。 如果Redis服务器中的内存碎⽚已经很⼤,可以通过安全重启的⽅式减⼩内存碎⽚:因为重启之后, Redis重新从备份⽂件中读取数据,在内存中进⾏重排,为每个数据重新选择合适的内存单元,减⼩内存 碎⽚。

优化内存占用

  1. 利⽤jemalloc特性进⾏优化:由于jemalloc分配内存时数值是不连续的,因此 key/value字符串变化⼀个字节,可能会引起占⽤内存很⼤的变动;例如,如果key的⻓度如果是13个字节,则SDS为17字节,jemalloc分配32字节;此时将key⻓度 缩减为12个字节,则SDS为16字节,jemalloc分配16字节;则每个key所占⽤的空间都可以缩⼩⼀ 半。
  2. 使⽤整型/⻓整型:整型/⻓整型,Redis会使⽤int类型(8字节)存储来代替字符串,可以节省更多空间。因此在可以 使⽤⻓整型/整型代替字符串的场景下,尽量使⽤⻓整型/整型。
  3. 利⽤共享对象,可以减少对象的创建(同时减少了redisObject的创建),节省内存空间。⽬前redis中的 共享对象只包括10000个整数(0-9999);可以通过调整 OBJ_SHARED_INTEGERS 参数提⾼共享对象的 个数;
  4. 缩短键值对的存储⻓度:键值对的⻓度是和性能成反⽐的,在 key 不变的情况下,value 值越⼤操作效率越慢,当键值对内容较⼤时,还会带来⼏个问题;如:(1)内容越⼤需要的持久化时间就越⻓,需要挂起的时间越⻓,Redis 的性能就会越低;(2)内容越⼤在⽹络上传输的内容就越多,需要的时间就越⻓,整体的运⾏速度就越低;(3)内容越⼤占⽤的内存就越多,就会更频繁的触发内存淘汰机制,从⽽给 Redis 带来了更多的运⾏负 担。因此在保证完整语义的同时,我们要尽量的缩短键值对的存储⻓度,必要时要对数据进⾏序列化和压缩 再存储。

个人学习整理,有错欢迎指正。