OOM 概述
OOM(Out of Memory),即内存不足,这在应用程序中非常常见。当 Redis 发现内存不足,其会向客户端发送一个错误消息并关闭与客户端的连接,导致服务不可用。当然,Redis 在出现 OOM 时也会拒绝写入操作,并向客户端发送错误消息。
OOM 的原因
1. Redis 运行内存时未设限制
如果 Redis 的运行内存没有设置限制或设置过小,就会导致 Redis 的内存用尽。可以通过修改 redis.conf 中的 maxmemory 参数来解决。
maxmemory <bytes>
其中 bytes 是可用的最大内存。如果 Redis 超过了最大内存限制,Redis 将会在首次尝试写入时返回错误,并关闭与客户端的连接。
2. Redis 的内存碎片
内存碎片指空闲内存块之间存在无法使用的内存空间。当 Redis 内存碎片较多时,即使有足够的内存,也会出现 OOM 的情况。Redis 内部使用 jemalloc 内存分配器来管理内存,可以使用如下命令来查询 Redis 的内存使用情况:
redis-cli info memory
从输出结果中,可以找到 consumed_memory 和 fragmentation_ratio 两个变量。consumed_memory 表示 Redis 当前消耗内存的大小,而 fragmentation_ratio 表示 Redis 的内存碎片率。
3. Redis 的内存泄漏
内存泄漏分为未释放的动态分配内存和永久性分配内存两种。在 Redis 中,大多数内存泄漏与应用程序本身有关,特别是在使用 Lua 脚本时,容易出现内存泄漏。
解决方案
1. Redis 的内存清理策略
当 Redis 内存不足时,采用以下清理策略:
- noeviction:当 Redis 内存不足时,直接拒绝写入操作,向客户端发送 OOM 错误消息,阻塞所有命令;
- allkeys-lru:Redis 会在数据集中搜索哪个键最近最少使用,然后删除该键;
- allkeys-random:Redis 随机删除数据集中的任意一个键;
- volatile-lru:Redis 只在数据集中搜索可以过期的键中找到最近最少使用(LRU)的键,并删除该键。如果数据集没有足够的过期键,则尝试更新设置最少使用数字的键,然后再次查找可以过期的键,并重复此过程;
- volatile-random:Redis 随机搜索可以过期的键,如果数据库没有过期键,则随机删除任意一个键;
- volatile-ttl:Redis 将键按过期时间排序,并根据空间需求删除尽可能接近过期时间的键。
以上清理策略可以通过以下命令设置:
maxmemory-policy <policy>
其中 policy 的类型是字符串,可以是以上清理策略中的任意一种。
2. 压缩 Redis 内存
当 Redis 内存碎片较多时,可以使用以下方法进行压缩:
redis-cli --bigkeys
该命令会输出 Redis 中大的 key,可以使用以下命令删除其它冗余数据:
redis-cli hdel <key> <field>
3. Redis 的监控和诊断
当 Redis 发生 OOM 时,可以使用以下命令进行监控和诊断:
redis-cli --stat
该命令会输出与 Redis 相关的统计信息,包括内存使用情况、操作次数、命中率等。通过该指令可以快速确定 Redis 的性能瓶颈和潜在问题。
总结
Redis 中出现 OOM 错误,通常有以下三个原因:
- Redis 运行内存未设置限制;
- Redis 内存碎片过多;
- Redis 出现内存泄漏。
可以通过以下方法解决 Redis 中 OOM 错误:
- 通过 Redis 内存清理策略进行内存管理;
- 压缩 Redis 内存;
- 监控和诊断 Redis 的内存使用情况。
参考文献
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/648fc0d248841e9894de7d81