【Redis】线上7000w+ keys && 16G内存100%的排查修复经历

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 起因 我们使用的一直是阿里云的redis, 我们并非高并发应用, 主要也就是拿来做分布式锁和少量的缓存, 基本不怎么需要维护, 昨天下午突然收到一封告警邮件, 线上redis内存使用100%, 瞬间神经绷紧感觉上控台确认.

起因

我们使用的一直是阿里云的redis, 我们并非高并发应用, 主要也就是拿来做分布式锁和少量的缓存, 基本不怎么需要维护, 昨天下午突然收到一封告警邮件,
image
线上redis内存使用100%, 瞬间神经绷紧感觉上控台确认.
image
这是一个16G的线上实例, 平时不到50%

排查修复

info信息

image

基本使用都是默认的db 0, 看到keys已经七千多万, 设置了过期的时间key只有173W..

查找bigkey, 想办法先释放一部分keys

先挂上bigkeys的命令

$ redis-cli -h  xxx.redis.rds.aliyuncs.com -a xxx --bigkeys

image
发现几个出现频率较高的大string key, 和开发同事确认, 是最近添加的redis缓存, 缓存时间为10天, 通知先关闭开关, 避免影响已经运行的任务, 进redis暂时先删除几个比较大的keys看看, 释放了少量内存
image

BoundValueOperations<String, String> contactListCache = kvLockTemplate.boundValueOps("athena.cache.contactlist" + user.getId());

现在key太多, 如果直接keys效率非常低下, 好在redis原生提供了SCAN, 可以迭代遍历, 写个简单的python脚本用scan每次扫描100W,把相关的keys给删掉.

import redis

def clean_excess(host='xxx.redis.rds.aliyuncs.com', port=6379, db=0,
                     password='xxx', pattern=None):
    _redis = redis.StrictRedis(host=host, port=port, db=db, password=password)
    i = None
    while i != 0:
        if i is None: i = 0
        print('>> scan index', i)
        _scan = _redis.scan(i, match=pattern, count="1000000")
        i, l = _scan
        if l:
            for _i in l:
                print("-- delete key {}".format(_i))
                _redis.delete(_i)
if __name__ == '__main__':
    clean_excess(pattern="athena.cache.contactlist*")

运行完成后内存使用率降到了 45%, 到这里内存问题算是解决了.
image

image

用awk快速抽样统计下keys的比例

好在我们都是keyPrefix + 数字id这样的格式, 这里抽样100W看下比例,

redis-cli -h  xxx.redis.rds.aliyuncs.com -a xxx scan 0 count 1000000 | awk -F '[0-9]' '{s=NF>0?$1:$0;print s}' | sort  | uniq -c | sort -n

image
找开发同学确认下, 这里 ip.try.counter 原本是某个版本用来锁定用户ip尝试登陆的..居然没设置过期时间, 其余的key多多少少都带了一些神奇的逻辑, 就基本没法动了....内心是崩溃的 那么先把这些清理掉

import redis

def clean_excess(host='xxx.redis.rds.aliyuncs.com', port=6379, db=0,
                     password='xxx', pattern=None):
    _redis = redis.StrictRedis(host=host, port=port, db=db, password=password)
    i = None
    while i != 0:
        if i is None: i = 0
        print('>> scan index', i)
        _scan = _redis.scan(i, match=pattern, count="1000000")
        i, l = _scan
        if l:
            for _i in l:
                print("-- delete key {}".format(_i))
                _redis.delete(_i)
if __name__ == '__main__':
    clean_excess(pattern="ip.try.counter.*")

image
image

跑了大概九个小时... 清理完后还剩了三千多万key, 内存倒是没怎么释放 其余的问了开发同学基本不能动. 使用率现在维持在50%以下暂时就不动了

结语

  • 关于redis内存逐出策略的问题, 阿里云默认给出的maxmemory刚好是等于你的内存配置大小的,也就是内存使用率100%了才会触发, 逐出策略默认是valatile-ttl只会逐出设置了过期时间的key, 相对于我们的情况, 大部分都是没设置过期时间基本就是杯水车薪. 如果改变策略为allkeys-xx 进行有效逐出,还是会影响到业务的正常运行
    image

说到底还是需要规范使用者的习惯, 该设置过期时间的不能偷懒, 确实有大内存需求的独立分配资源.

  • 其实有很多不错的现成的工具可以对redis进行诊断 可以参考下 https://scalegrid.io/blog/the-top-6-free-redis-memory-analysis-tools/
    不过这里rdb只能分析dump.rdb文件, 其他几个工具试用了下对于keys数量级过大效率都略低下, 好在我们keys命名还算有一定规律所以自己写了个简单脚本去抽样统计, 比较喜欢的是redis-memory-for-key(只是用来统计具体key的内存占用情况),也可能我使用姿势不对吧 欢迎一起探讨
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
存储 缓存 NoSQL
Redis Quicklist 竟让内存占用狂降50%?
【10月更文挑战第11天】
42 2
|
14天前
|
弹性计算
阿里云2核16G云服务器多少钱?亲测ECS内存型r8i租赁价格
阿里云2核16G云服务器,内存型r8i实例1年6折优惠后价格为1901元,月付334.19元,按小时计费0.696221元。更多配置及优惠详情,请访问阿里云ECS页面。
|
1月前
|
设计模式 Java Android开发
安卓应用开发中的内存泄漏检测与修复
【9月更文挑战第30天】在安卓应用开发过程中,内存泄漏是一个常见而又棘手的问题。它不仅会导致应用运行缓慢,还可能引发应用崩溃,严重影响用户体验。本文将深入探讨如何检测和修复内存泄漏,以提升应用性能和稳定性。我们将通过一个具体的代码示例,展示如何使用Android Studio的Memory Profiler工具来定位内存泄漏,并介绍几种常见的内存泄漏场景及其解决方案。无论你是初学者还是有经验的开发者,这篇文章都将为你提供实用的技巧和方法,帮助你打造更优质的安卓应用。
|
2月前
|
缓存 监控 NoSQL
阿里面试让聊一聊Redis 的内存淘汰(驱逐)策略
大家好,我是 V 哥。粉丝小 A 面试阿里时被问到 Redis 的内存淘汰策略问题,特此整理了一份详细笔记供参考。Redis 的内存淘汰策略决定了在内存达到上限时如何移除数据。希望这份笔记对你有所帮助!欢迎关注“威哥爱编程”,一起学习与成长。
|
2月前
|
监控 Java Linux
redisson内存泄漏问题排查
【9月更文挑战第22天】在排查 Redisson 内存泄漏问题时,首先需确认内存泄漏的存在,使用专业工具(如 JProfiler)分析内存使用情况,检查对象实例数量及引用关系。其次,检查 Redisson 使用方式,确保正确释放资源、避免长时间持有引用、检查订阅和监听器。此外,还需检查应用程序其他部分是否存在内存泄漏源或循环引用等问题,并考虑更新 Redisson 到最新版本以修复潜在问题。
|
2月前
|
存储 Prometheus NoSQL
Redis 内存突增时,如何定量分析其内存使用情况
【9月更文挑战第21天】当Redis内存突增时,可采用多种方法分析内存使用情况:1)使用`INFO memory`命令查看详细内存信息;2)借助`redis-cli --bigkeys`和RMA工具定位大键;3)利用Prometheus和Grafana监控内存变化;4)优化数据类型和存储结构;5)检查并调整内存碎片率。通过这些方法,可有效定位并解决内存问题,保障Redis稳定运行。
|
3月前
|
存储 NoSQL 算法
Redis内存回收
Redis 基于内存存储,性能卓越,但单节点内存不宜过大,以免影响持久化或主从同步。可通过配置 `maxmemory` 限制最大内存。内存达到上限时,Redis采用两种策略:内存过期策略和内存淘汰策略。过期策略包括惰性删除和周期删除,后者分为 SLOW 和 FAST 模式。内存淘汰策略有八种,如 LRU、LFU 和随机淘汰等,用于在内存不足时释放空间。官方推荐使用 LFU 算法。
Redis内存回收
|
2月前
|
缓存 NoSQL 算法
14)Redis 在内存用完时会怎么办?如何处理已过期的数据?
14)Redis 在内存用完时会怎么办?如何处理已过期的数据?
56 0
|
2月前
|
存储 缓存 NoSQL
Redis 过期删除策略与内存淘汰策略的区别及常用命令解析
Redis 过期删除策略与内存淘汰策略的区别及常用命令解析
71 0
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
378 0