zoukankan      html  css  js  c++  java
  • Redis内存使用率增长的一些解决思路

    可以把Redis存储想象成一个有进有出的蓄水池

    哪些情况会是Redis服务的内存使用率不断升高呢

    1、将大量新写入Redis的key的TTL设置为-1,永远不过期,也就相当于一直往容量一定的蓄水池中加水但是不往外面排水,这时内存使用率一直升高是很显然的。

    2、大量新写入Redis的eky的TTL时间设置的有点长,相当于这样的场景:蓄水池的水龙头快速往水池中加水,但是排水口从蓄水池中排水的速度远小于加水的速度,那么此时Redis的内存使用率也会一直升高!

    一些建议

    1、建议把项目中设置Redis的key的地方写在一起,方便知道线上代码写入Redis的key的格式有哪些(因为Redis不像关系型数据库那样有很多很好的可视化工具支持查看表结构、表字段等信息~)

    2、对于一些非固定的数据,不建议将TTL值设置为-1,比如用户的一些常用信息我们会缓存到redis中,这样确实降低了读取数据库的IO,提高了效率,但是互联网的用户流动量比较大,有可能存入到Redis中的用户信息,这个用户到后面不玩我们的产品了,他也没有注销~ 这时候我们再redis中存储的其实就是一条永久的无用的脏数据了!!!—— 实际上建议存24小时或者其他时间,每天只存一些当天活跃或者7天活跃的用户~~ 这样效果会更好 —— 网站的session一般都会存7天。

    3、Redis的TTL,设置的要合理一些~ 不要太长,这样排水口的水流出的会很慢,如果进水口进入的水量增加的话,也会使Redis的内存使用率爆增!

    问题描述

    线上Redis监控发现某一段时间redis的内存使用率在一直升高,当时的时间点是升高的时间:

    经过线上处理,首先是停止Redis内存继续往上升~然后可以去掉一些无用的key~最终使内存使用率降下来。

    记得根据实际情况解决问题 ******

    ❗️但是,提醒一下:需要先评估一下,删除这些key,对于业务有没有特别大的影响!如果影响很小,是一个很边缘的需求,可以这么搞。 

    必须的key不要删除

    如果删除这些key,对于业务的影响很大的话(比如用户每日的任务等,TTL到当天的24点,删除的话用户任务白做了!),这时候就不要去想删除key去解决内存使用率增高的问题了!

    建议:适当的去调整一下新的进入Redis中这些key的TTL值~ 或者 升级一下Redis机器~现在的云服务器基本都支持平滑升级,并且升级还是很快的,可以将损失降到很低~

    非必要的key可以批量删除

    我们自己的业务中,删除这些key,对于正常业务没有任何影响!

    ❗️先在业务代码中,取消往Redis中写入这些key的逻辑 ~~ 保证没有新的key进入Redis,然后再删除 ———— 删除完,等Redis的内存下来以后,可以再加回来相关的逻辑,但是TTL不要设置的太大了!!!

    使用一个demo来说明一下解决思路 ***

    在本地docker搭建一下redis服务,使用db1,里面有1个key

     

    写一个python脚本往里面分别插入3种不同的key

    import random
    from datetime import date
    
    import redis
    
    
    today_str = date.today().strftime("%Y-%m-%d")
    print(">>> ", today_str, type(today_str))
    
    # redis key 的格式
    key1 = "redis_demo:test1:{}:{}"  # redis_demo:test1:(2021-12-25):(随机字符串)
    key2 = "redis_demo:test2:{}:{}"  # redis_demo:test1:(2021-12-25):(随机字符串)
    key3 = "redis_demo:test3:{}:{}"  # redis_demo:test1:(2021-12-25):(随机字符串)
    
    # redis链接
    # 注意这里我用的是 db1 ———— 没有用Redis集群,用的是一个Redis实例
    r = redis.Redis(host="127.0.0.1", port=6379, db=1)
    
    
    # 往Redis中模拟插入1w个key1、key2、key3类型的字符串
    for i in range(10000):
        curr_key1 = key1.format(today_str, str(random.randint(0,1000000)))
        curr_key2 = key2.format(today_str, str(random.randint(0,1000000)))
        curr_key3 = key3.format(today_str, str(random.randint(0,1000000)))
        curr_value = str(random.randint(0,10000))
    
        # 都在10000秒后失效
        r.set(curr_key1, curr_value, 10000)
        r.set(curr_key2, curr_value, 10000)
        r.set(curr_key3, curr_value, 10000)

    看看db1中的dbsize

    如果线上key比较多千万不能使用 keys * 相关命令!会阻塞Redis服务!

    如果线上key比较多千万不能使用keys *相关命令!会阻塞Redis服务!

    使用scan命令找key

    scan 0 match redis_demo:test1* 

    但是找出来以后,不可能一个一个执行 del 命令删除~~ 太浪费时间了。

    可以在终端执行 redis-cli 相关命令。

    使用redis-cli命令将所有key输出到文件中然后写脚本del相关的key ***

    选择db1,然后将match到的key输出到文件中:

    redis-cli -h 127.0.0.1 -p 6379 -n 1 --scan --pattern "redis_demo:test1*" > redis_demo的test1的key.txt

    也可以看看文件有多少行:

    cat redis_demo的test1的key.txt |wc -l

    —— 也就是有9962个key,里面都是完整的redis的key,后面可以写一个脚本,一行一行从文件中读取这些key,然后在redis中执行del操作删除key!

    使用redis-cli配合xargs命令使用命令删除scan命令获取到的key ***

    注意:需要选择 db1  —— 实际上可以同时删除1000条数据~~

    redis-cli -h 127.0.0.1 -p 6379 -n 1 --scan --pattern "redis_demo:test1*" |xargs -L 10 redis-cli -h 127.0.0.1 -p 6379 -n 1  del

    把test2与test3也一起删掉,可以同时删1000条数据

    最后再进去看看只剩下一开始的那个key了

    参考文章

    Redis在命令行中操作指定数据库下的key

    redis cli命令

    redis scan 优雅的批量删除

    深入理解Redis的scan命令

    Redis scan命令解析——替代keys命令可以在生产环境使用实现遍历

    Redis Scan 原理解析与踩坑 

    ~~~

  • 相关阅读:
    System.Web.Mvc.HttpHeadAttribute.cs
    System.Web.Mvc.HttpOptionsAttribute.cs
    System.Web.Mvc.HttpDeleteAttribute.cs
    sqlite-dbeaver-heidisql
    java实现圆周率
    java实现圆周率
    java实现圆周率
    java实现圆周率
    java实现圆周率
    java实现最近距离
  • 原文地址:https://www.cnblogs.com/paulwhw/p/15731229.html
Copyright © 2011-2022 走看看