Redis 性能调优——内存优化

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/smartbetter/article/details/97971151

本篇主要介绍 Redis 内存优化的一些技巧。

1.内存消耗

1、内存使用统计

Redis 可以通过 info memory 命令来查看内存使用情况,属性说明如下:

属性名 属性说明
used_memory Redis 分配器分配的内存量,也就是实际存储数据的内存总量
used_memory_human 以可读格式返回 Redis 使用的内存总量
used_memory_rss 从操作系统的角度,Redis 进程占用的总物理内存
used_memory_peak 内存分配器分配的最大内存,代表 used_memory 的历史峰值
used_memory_peak_human 以可读的格式显示内存消耗峰值
used_memory_lua Lua 引擎所消耗的内存
mem_fragmentation_ratio used_memory_rss/used_memory 比值,表示内存碎片率,used_memory_rss - used_memory 就是内存碎片的大小
mem_allocator Redis 所使用的内存分配器,默认 jemalloc

2、内存消耗划分

used_memory,Redis分配器分配的内存量
自身内存
800K左右
对象内存
key对象
value对象
缓冲内存
客户端缓冲区
复制缓冲区
AOF缓冲区
Lua 内存

2.缓冲内存

1.客户端缓冲区

客户端分为普通客户端(Jedis)、slave 客户端、pubsub 客户端。

输入缓冲区:

流程:客户端 -> 命令(输入缓冲区) -> 处理命令

注意:最大 1GB,超过后会被强制断开,不可动态设置。

输出缓冲区:

输出缓冲区对应的配置规则是:client-output-buffer-limit < class> < hard limit> < soft limit> < soft seconds>

< class>:客户端类型,分为三种(a)normal 普通客户端;(b)slave 从节点用于复制,伪装成客户端;(c)pubsub 发布订阅客户端。
< hard limit>:如果客户端使用的输出缓冲区大于 < hard limit>,客户端会被立即关闭。
< soft limit> 和 < soft seconds>:如果客户端使用的输出缓冲区超过了 < soft limit> 并且持续了 < soft limit> 秒,客户端会被立即关闭。

普通客户端(Jedis)默认 client-output-buffer-limit normal 0 0 0,默认没有限制客户端缓冲,注意防止大的命令或者 monitor。
slave 客户端默认 client-output-buffer-limit slave 256mb 64mb 60,注意从节点不要超过 2 个。
pubsub 客户端默认 client-output-buffer-limit pubsub 32mb 8mb 60,使用场景并不多,注意根据实际场景适当调试。

2.复制缓冲区

此部分内存独享,考虑部分复制,默认 1 MB,可以设置更大。

3.AOF 缓冲区

AOF 重写期间,AOF 的缓冲区没有容量限制。

3.对象内存

key对象:不要过长,量大不容忽视;
value对象:ziplist、intset 等优化方式。

4.内存管理

1.内存设置上限

定义实例最大内存,便于管理机器内存,一般要预留 30%。动态调整内存上限的命令:

	redis> config set maxmemory 6GB
	redis> config rewrite

2.内存回收策略

1、删除过期键值

惰性删除:访问 key -> expired dict -> del key
定时删除:每秒运行 10 次,采样删除。

2、内存溢出控制策略

超过 maxmemory 后触发相应策略,由 maxmemory-policy 控制。

  • Noeviction:默认策略,不会删除任何数据,拒绝所有写入操作并返回错误信息 “(error) OOM command not allowed when used memory”,此时 Redis 只响应读操作由 maxmemory-policy 控制。
  • Volatile-lru:根据 LRU 算法删除设置了超时属性(expire)的键,直到腾出足够空间为止,如果没有可删除的键对象,回退到 Noeviction 策略。
  • Allkeys-lru:根据 LRU 算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。
  • Allkeys-random:随机删除所有键,直到腾出足够空间为止。
  • Volatile-random:随机删除过期键,直到腾出足够空间为止。
  • Volatile-ttl:根据键值对象的 ttl 属性,删除最近将要过期的数据,如果没有,回退到 Noeviction 策略。

5.内存优化

1、合理的选择优化数据结构

2、客户端缓冲区内存优化

示例:一次内存暴增。Redis Sentinel 架构,maxmemory 设置为 4GB,发现主节点使用内存 4GB,从节点使用内存 2GB。

排查过程:主节点是否有大批量的写入?查看监控发现没有。
主从不一致?主从都执行 dbsize 命令,发现都是 23254136。
客户端溢出?实际上已经收到报警了,最大输出缓冲区溢出了,这个时候我们完全可以使用 client list 命令找到 omem 为 0 的客户端连接:

	redis-cli client list | grep -v "omem=0"

发现有一个 oll=201261 omem=4675586842 cmd=monitor 的连接,根据 cmd==monitor 判断执行来源是 monitor,monitor 拉取了那么大数据,但是自身消费不了,这个时候我们可以将 monitor 直接干掉,进行内存回收。

预防策略:

  • 运维层面:线上 Redis 禁用 monitor(rename-command)命令;适度限制缓冲区大小;
  • 开发层面:理解 monitor 原理,也可以短暂寻找热点 key(本地执行);使用 CacheCloud 可以直接监控到。

3、其他方法

  • 不要忽视 key 的长度,1 亿个键,1 个字节也是节省;
  • 序列化和压缩方法,拒绝 java 原生,采用 protobuf、keyo、snappy 等。
展开阅读全文

没有更多推荐了,返回首页