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 原理解析与踩坑 

    ~~~

  • 相关阅读:
    yolo_to_onnx ValueError: need more tan 1 value to unpack
    yolo_to_onnx killed
    C++ 实现二维矩阵的加减乘等运算
    Leetcode 1013. Partition Array Into Three Parts With Equal Sum
    Leetcode 1014. Best Sightseeing Pair
    Leetcode 121. Best Time to Buy and Sell Stock
    Leetcode 219. Contains Duplicate II
    Leetcode 890. Find and Replace Pattern
    Leetcode 965. Univalued Binary Tree
    Leetcode 700. Search in a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/paulwhw/p/15731229.html
Copyright © 2011-2022 走看看