Redis开发与运维笔记-理解内存

网友投稿 940 2022-10-03

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

Redis开发与运维笔记-理解内存

参考书籍:Redis开发与运维[1]

理解内存

内存消耗

内存使用统计

info memory

属性名属性说明
used_memoryRedis分配器分配的内存总量,也就是内部存储的所有数据的内存占用量
used_memory_human以可读的格式返回used_memory
used_memory_rss从操作系统的角度显示Redis进程占用的物理内存总量
used_memory_peak内存使用的最大值,表示used_memory的峰值
used_memory_peak_human以可读的格式返回used_memory_peak
used_memory_luaLua引擎所消耗的内存大小
mem_fragmentation_retioused_memory_rss/used_memory比值,表示内存碎片率
mem_allocatorRedis所使用的内存分配器。默认为jemalloc

重点关注的指标:used_memory_rss、used_memory以及mem_fragmentation_ratio

mem_fragmentation>1:说明存在内存碎片。<1:说明操作系统Reids内存交换(Swap)到硬盘。

内存消耗划分

Redis进程内消耗主要包括:自身内存+对象内存+缓存内存+内存碎片。

•对象内存 是Redis内存占用最大的一块,存储着用户所有的数据。•缓存内存

•客户端缓冲:接入到服务器TCP了解的输入输出缓冲。输入缓冲无法控制,最大为1G。输出缓冲通过client-output-buffer-limit控制。普通客户端要注意控制数量,从客户端不要挂载过多,订阅客户端要注意生产及消费消息的速度•复制积压缓冲区:用于实现部分复制功能,Redis提供的一个缓冲区,建议在合理范围内调大,可以有效避免全量复制•AOF缓冲区:这部分空间用于在Redis重写期间保存最近的写入命令。

•内存碎片容易出现高内存碎片的场景:

1.频繁做更新操作,例如频繁对已存在的键执行append、setrange等更新操作2.大量过期键删除,键对象过期删除后,释放的空间无法得到充分利用,导致碎片率上升。3.解决以上问题的方法:1)尽量做到数据对齐,2)安全重启

子进程内存消耗

主要发生在AOF/RDB重写时Redis创建的子进程内存消耗。总结如下:

1.Redis产生的子进程因为写时复制技术,并不需要消耗1倍的父进程内存。预留足够内存防止溢出即可2.需要设置sysctl vm.overcommit_memory=1允许内核可以分配所有物理内存,防止Redis进程执行fork时因系统剩余内存不足而失败3.排查当前系统是否支持并开启THP,如果开启建议关闭,防止copy-on-write期间内存过度消耗

内存管理

1.通过maxmemory设置Redis最大内存,需要注意的是由于碎片率的存在,实际消耗的内存可能会比maxmemory设置的更大2.通过config set maxmemory 2GB可以动态调整内存上限3.内存回收策略

•过期键删除策略:惰性删除和定时任务删除

•内存溢出控制策略,通过maxmemory-policy参数控制

•noeviction:默认策略,不删除数据。拒绝所有写入操作并返回客户端错误信息(error)OOM command not allowed when used memory,此时Redis只响应读操作

•vloatile-lru:根据LRU算法删除设置了超时的键,直到腾出足够空间。如果没有可删除的键,回退到noeviction

•allkeys-lru:根据LRU算法删除键。直到腾出足够空间

•allkeys-random:随机删除所有键,直到腾出足够空间

•volatile-ttl:根据键值对象的ttl,删除最近要过期的数据,如果没有,回退到noeviction策略

•设置了maxmemory时,当used_memory>maxmemory的状态下,会触发回收内存操作。应设置足够大的maxmemory避免长期处于这种状态下。

内存优化

redisObject对象

Redis存储的所有值对象在内部定义为redisObject结构体,内部结构如图:

•type:当前对象数据类型。可以使用type {key}查看对象所属类型•encoding:redis内部编码类型•lru:对象最后一次被访问的时间。可以使用object idletime {key}在不更新lru字段情况下查看键的空闲时间•refcount:记录对象被引用次数•*ptr:整数直接存储数据,否则为指向数据的指针

缩减键值对象

在保证业务的前提下,缩减键key和值value的长度。

共享对象池

Redis内部维护[0-9999]的整数对象池。优先使用整型数字有助于节省内存开销。需要注意的是对象池与maxmemory和LRU淘汰算法冲突。

字符串优化

字符串结构

Redis实现了自己的字符串结构,内部简单动态字符串(simple dynamic string,SDS).结构如图:

Redis字符串结构的特点:

1.字符串长度,已用长度,未用长度的操作复杂度为O(1)2.可用于保存字节数组,支持安全的二进制数据存储3.预分配机制,降低内存再分配次数4.惰性删除机制,字符串缩减后的空间不释放,作为预分配空间保留

预分配机制

1.第一次创建len属性等于数据实际大小,free等于0,不做预分配2.修改后如果free空间不够且数据小于1M,每次预分配一倍的容量3.修改后如果free空间不够且数据大于1M,每次预分配1MB的容量

字符串重构

JSON数据不一定要用string来存储,可以改为通过hash结构实现,同时使用hash结构也可以使用hmget、hmset命令支持字段的部分读取修改,而不用每次全部读取。

编码优化

主要是根据业务场景,选择合适的参数保证Redis使用合适的内部编码进而在性能和内存上进行取舍。

控制键的数量

客户端可以预估键的数量规模,把大量键映射到多个hash结构中降低键的数量

•hash的field可以记录原始key字符串,方便哈希查找•hash的value保存原始值对象,确保不要超过hash-max-ziplist-value限制

本章重点回顾

1.Redis实际内存消耗主要包括:键值对象、缓冲区碎片、内存碎片2.通过maxmemory控制Redis最大可用内存。内存溢出时,根据maxmemory-policy控制内存回收策略3.内存资源宝贵,可以通过以下手段优化内存使用:

1.精简键值对大小,使用高效二进制序列化工具2.使用对象共享池优化小整数对象3.数据优先使用整数4.优化字符串的使用,避免预分配造成的内存浪费5.使用ziplist压缩编码优化hash、list等结构,注重效率和空间的平衡6.使用intset编码优化整数集合

References

[1] Redis开发与运维: https://book.douban.com/subject/26971561/

上一篇:Mysql运维-数据库及表相关操作
下一篇:Linux 运维中最常用 150 个命令汇总
相关文章

 发表评论

暂时没有评论,来抢沙发吧~