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

本文涉及的产品
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介: 起因 我们使用的一直是阿里云的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
目录
相关文章
|
23天前
|
存储 NoSQL 算法
Redis内存回收
Redis 基于内存存储,性能卓越,但单节点内存不宜过大,以免影响持久化或主从同步。可通过配置 `maxmemory` 限制最大内存。内存达到上限时,Redis采用两种策略:内存过期策略和内存淘汰策略。过期策略包括惰性删除和周期删除,后者分为 SLOW 和 FAST 模式。内存淘汰策略有八种,如 LRU、LFU 和随机淘汰等,用于在内存不足时释放空间。官方推荐使用 LFU 算法。
Redis内存回收
|
30天前
|
存储 缓存 NoSQL
Redis内存管理揭秘:掌握淘汰策略,让你的数据库在高并发下也能游刃有余,守护业务稳定运行!
【8月更文挑战第22天】Redis的内存淘汰策略管理内存使用,防止溢出。主要包括:noeviction(拒绝新写入)、LRU/LFU(淘汰最少使用/最不常用数据)、RANDOM(随机淘汰)及TTL(淘汰接近过期数据)。策略选择需依据应用场景、数据特性和性能需求。可通过Redis命令行工具或配置文件进行设置。
41 2
|
1月前
|
JavaScript Java 开发工具
Electron V8排查问题之接近堆内存限制的处理如何解决
Electron V8排查问题之接近堆内存限制的处理如何解决
90 1
|
27天前
|
缓存 NoSQL Linux
【Azure Redis 缓存】应用中出现连接Redis服务错误(production.ERROR: Connection refused)的排查步骤
【Azure Redis 缓存】应用中出现连接Redis服务错误(production.ERROR: Connection refused)的排查步骤
|
28天前
|
缓存 监控 NoSQL
【Azure Redis 缓存】Azure Redis出现了超时问题后,记录一步一步的排查出异常的客户端连接和所执行命令的步骤
【Azure Redis 缓存】Azure Redis出现了超时问题后,记录一步一步的排查出异常的客户端连接和所执行命令的步骤
|
28天前
|
缓存 NoSQL 网络安全
【Azure Redis 缓存】Redis连接无法建立问题的排查(注:Azure Redis集成在VNET中)
【Azure Redis 缓存】Redis连接无法建立问题的排查(注:Azure Redis集成在VNET中)
|
29天前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Azure Redis读写比较慢/卡的问题排查
【Azure Redis 缓存】Azure Redis读写比较慢/卡的问题排查
|
2月前
|
监控 安全 Java
JVM内存问题之排查Direct Memory泄漏有哪些常用方法
JVM内存问题之排查Direct Memory泄漏有哪些常用方法
|
2月前
|
监控 Java Linux
JVM内存问题之如果堆内存一直缓慢上涨,如何解决
JVM内存问题之如果堆内存一直缓慢上涨,如何解决
279 1
|
2月前
|
NoSQL Redis
Redis性能优化问题之禁用内存大页,如何解决
Redis性能优化问题之禁用内存大页,如何解决