• 记一次redis批量删除千万量级key的实操与思考


    背景

    由于早期使用redis时,没有指定key过期时间,导致大量内存浪费,排查修改合理指定过期时间,历史数据的清理比我想象中有难度

    各种方案尝试

    使用Linux的xargs命令以及keys+del批量删除

    参考阿里云开发者社区文章,使用Linux的xargs命令以及keys+del批量删除

    1. begin
    2. sudo redis-cli -h localhost -p 6379 -a password keys "tryCurrentWorkerSwitch*" | xargs sudo redis-cli -h localhost -p 6379 -a password del
    3. end

    此方案有两个问题:

    1. keys命令是阻塞的,会影响redis的线上流量正常使用
    2. keys命中的key量多了之后,执行keys命令时间会很长,同时xargs拼接del命令的时候会超出参数的长度限制

    使用Linux的xargs命令以及scan+del批量删除

    参考redis官方手册,使用scan命令查找key不会阻塞

    1. begin
    2. sudo redis-cli -h localhost -p 6379 -a password scan 0 match "tryCurrentWorkerSwitch*" count 1000 | xargs sudo redis-cli -h localhost -p 6379 -a password del
    3. end

    此方案的问题在于count小的话要执行次数太多,需要脚本化循环处理才有可能实施,count大的话xargs拼接del命令的时候也会超出参数的长度限制

    最终方案:使用shell脚本及scan+del批量删除

    参考网友现成的方案,考虑key多执行时间长以及日志较多,不挂起执行脚本实现批量删除,并删除不挂起执行日志文件防止日志文件过大。

    scantodel.sh内容:

    1. #!/bin/bash
    2. if [ "$#" -lt 3 ]
    3. then
    4. echo "Scan keys in Redis matching a pattern using SCAN (safe version of KEYS)"
    5. echo "Usage: $0 [pattern] <host> [port] [database] [count] [second]"
    6. exit 1
    7. fi
    8. pattern=${1:-}
    9. host=${2:-}
    10. port=${3:-6379}
    11. database=${4:-0}
    12. count=${5:-5000}
    13. second=${6:-1}
    14. if [ ! -n "$pattern" ] ;then
    15. echo "pattern shoud not be empty!"
    16. fi
    17. cursor=-1
    18. keys=''
    19. while [ $cursor -ne 0 ]; do
    20. if [ $cursor -eq -1 ]
    21. then
    22. cursor=0
    23. fi
    24. reply=`redis-cli -h "$host" -p "$port" -n "$database" SCAN $cursor MATCH $pattern COUNT $count`
    25. cursor=`expr "$reply" : '\([0-9]*[0-9 ]\)'`
    26. keys=${reply#[0-9]*[[:space:]]}
    27. redis-cli -h "$host" -p "$port" -n "$database" DEL $keys
    28. sleep $second
    29. done

    执行脚本

    1. begin
    2. sudo nohup sh scantodel.sh *pattern* 127.0.0.1 6379 0 5000 1
    3. rm -f nohup.out
    4. end

    实操效果

    思考

    除了前面提到的没有设置过期时间,还有个问题是这种量级的key。千万级别的key听起来很牛的样子,实际憨得不行,完全可以冗余hash对key进行归类,当然也需要避免一个hash元素过大,需要合理的设计key及其结构。

  • 相关阅读:
    vue2中,vue-easytable组件的使用(一)——简介和基本使用
    Linux 设置快捷命令
    顾客点餐系统-----操作菜品JDBC代码的编写(2)
    进程和任务管理计划
    Find My头盔|苹果Find My技术与头盔结合,智能防丢,全球定位
    Django学习笔记二:数据库配置
    Ubuntu22.04安装CUDA深度学习环境&&cuda principle
    laravel valet
    Rust可空类型Option
    关于Hbase使用出现java.io.IOException: java.lang.reflect.InvocationTargetException解决
  • 原文地址:https://blog.csdn.net/qq525099302/article/details/79038441