redis-cli KEYS "pattern" | xargs redis-cli DEL

Redis keys命令支持模式匹配,但是del命令不支持模式匹配,有时候需要根据一定的模式来模糊删除key,这时只能结合shell命令来完成了。 具体命令是:

redis-cli KEYS "pattern" | xargs redis-cli DEL 
其中pattern是keys命令支持的模式,这样就可以模糊删除key了。服务器上测试删除150万条数据的效率也是很高的。

问题是只能删除单机,集群模式下无法模糊删除;

线上redis cluster需要删除几百万的keys,要删除keys的前缀是usertags_uid_*

【解决方案】
第一种方式:
首先通过scan在三个主节点(假设集群是三主三从)扫描出匹配前缀的keys
redis-cli -c -h $host1 -p $port1 --scan --pattern "usertags_uid_*" > /tmp/node1.log
redis-cli -c -h $host2 -p $port2 --scan --pattern "usertags_uid_*" > /tmp/node2.log
redis-cli -c -h $host3 -p $port3 --scan --pattern "usertags_uid_*" > /tmp/node3.log
然后写个简单脚本进行删除,比如

#!/bin/bash
host=$1
port=$2
file=$3
if [ $# -ne 3 ];then
echo "Usage: $0 ip port file"
exit
fi
cat $file|while read line
do
redis-cli -c -h $host -p $port del $line
done

最后调用脚本删除
sh del_redis_keys.sh $host1 $port1 node1.log

第二种方式:
使用redis的pipeline进行删除
首先通过scan扫描出匹配前缀的keys
redis-cli -c -h $host1 -p $port1 --scan --pattern "usertags_uid_*" > /tmp/node1.log
redis-cli -c -h $host2 -p $port2 --scan --pattern "usertags_uid_*" > /tmp/node2.log
redis-cli -c -h $host3 -p $port3 --scan --pattern "usertags_uid_*" > /tmp/node3.log
然后把这些keys导入mysql中
最后利用redis协议删除

第一种方式效率很低,一秒只能删除大概200到300个keys
第二种方式效率很高,可以达到redis的极限
两种删除方式我们线上都在用,为了方便使用都写成了脚本,第一种方式适合keys少的情况,第二种方式适合keys多的情况

【具体实现】
1、创建表
mysql> show create table del_redis_keys\G
*************************** 1. row ***************************
       Table: del_redis_keys
Create Table: CREATE TABLE `del_redis_keys` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `keyname` varchar(60) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_kn` (`keyname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

2、编辑SQL文件
cat del_redis_keys.sql
select concat("*2\r\n",'$3\r\n','DEL\r\n','$',length(redis_key),'\r\n',redis_key,'\r') from (select concat('',keyname) as redis_key from del_redis_keys) as t;

3、脚本
#!/bin/bash
source /etc/profile
rc_member=$1
key_pattern_name=$2
time=`date "+%m%d%H%M"`
manage_db_user="user"
manage_db_pass="password"
manage_db_host="10.10.64.100"
manage_db_port="3306"
manage_config_db="DB_M"
manage_config_tb="tb_redis_node"
base_dir=$(cd `dirname $0`; pwd)   
del_redis_keys_sql="${base_dir}/del_redis_keys.sql"
scan_keys_dir="${base_dir}/logs/group_${rc_member}_${time}"
error_log="/tmp/del_redis_keys.log"
error_log2="/tmp/del_redis_keys.log2"
redis_cli="/server/redis_cluster/src/redis-cli"
mysql_server="/server/mysql/bin/mysql"
lv1="\033[42;30m"
lv2="\033[0m"
end="\033[0m"
red="\033[45;37m"
if [ $# -ne 2 ];then
    echo "Usage: $0 rc_member key_pattern"
    exit
fi
if ! [ -f "$del_redis_keys_sql" ];then
    echo -e "${red}${del_redis_keys_sql}文件不存在,请检查${end}"
    exit
fi
if ! [ -f "$redis_cli" ];then
    echo -e "${red}${redis_cli}不存在,请检查${end}"
    exit
fi
if ! [ -f "$mysql_server" ];then
    echo -e "${red}${mysql_server}不存在,请检查${end}"
    exit
fi
if ! [ -d "$scan_keys_dir" ];then
    mkdir -p $scan_keys_dir
fi

echo "keys所在目录: $scan_keys_dir"
sum=0
check_key=0
redis_node_list=`$mysql_server -u $manage_db_user -p$manage_db_pass -h $manage_db_host -P $manage_db_port $manage_config_db -N -e "select concat_ws('|',hostip,port) from $manage_config_tb where type=1 and status=1 and rc_member=$rc_member;"`  #线上将status修改为1
for redis_info in $redis_node_list
do
        host=`echo $redis_info | awk -F"|" '{print $1}'`
        port=`echo $redis_info | awk -F"|" '{print $2}'`
        befer_del_cnt=`$redis_cli -c -h $host -p $port info Keyspace|grep -v Keyspace|awk -F, '{print $1}'|awk -F: '{print $2}'|awk -F= '{print $2}'`
        #redis导出要删除的keys
        $redis_cli -c -h $host -p $port --scan --pattern "*${key_pattern_name}*" > $scan_keys_dir/${host}_${port}.log
        key_num=`wc -l $scan_keys_dir/${host}_${port}.log|awk '{print $1}'`
        sum=$[$key_num+$sum]
        echo -e "${lv1}$host:$port${lv2}"
        #清空del_redis_keys表
        $mysql_server -u $manage_db_user -p$manage_db_pass -h $manage_db_host -P $manage_db_port $manage_config_db -N -e "truncate table del_redis_keys;"
        #导入要删除的keys
        $mysql_server -u $manage_db_user -p$manage_db_pass -h $manage_db_host -P $manage_db_port $manage_config_db --local-infile=1 --show-warnings -N -e "load data local infile '$scan_keys_dir/${host}_${port}.log' into table del_redis_keys (keyname);" > $error_log
        #判断导出的keys和导入的keys数目是否相等
        mysql_keys_num=`$mysql_server -u $manage_db_user -p$manage_db_pass -h $manage_db_host -P $manage_db_port $manage_config_db -N -e "select count(1) from del_redis_keys;"`
        if [ $key_num -ne $mysql_keys_num ];then
            echo -e "${red}导入数据库的keys数目不正确${end}"
            exit
        fi
        #检验导入时是否有warning,如果有退出并提示
        if [ -s "$error_log" ];then 
            warning_cnt=`grep -o Warning $error_log|wc -l|awk '{print $1}'`
            if [ $warning_cnt -ge 1 ];then
                echo -e "${red}导入数据报错,请看$error_log${end}"
                exit
            fi
        fi
        #检查keys是否正确,只在第一个节点检查,后面节点不再重复检查
                if [ $check_key -eq 0 ];then
                    echo "请检查数据库里要删除的keys是否正确"
                    echo "$mysql_server -u $manage_db_user -p$manage_db_pass -h $manage_db_host -P $manage_db_port $manage_config_db -e 'select * from del_redis_keys limit 20;'"
                    #echo "select * from del_redis_keys limit 50;"
                    while true; do
                        read -p "检查完keys之后选择继续或退出(yes|no): " yn
                        case $yn in
                                yes ) break;;
                                no ) exit;;
                                * ) echo "Please input yes or no";;
                        esac
                    done
                    while true; do
                        read -p "确认继续吗(yes|no): " yn
                        case $yn in
                                yes ) break;;
                                no ) exit;;
                                * ) echo "Please input yes or no";;
                        esac
                    done
                fi
                check_key=$[check_key+1]
        #删除keys
        $mysql_server --raw --skip-column-names --default-character-set utf8 -u $manage_db_user -p$manage_db_pass -h $manage_db_host -P $manage_db_port $manage_config_db -A < ${del_redis_keys_sql} | $redis_cli -h $host -p $port --pipe >> $error_log2 2>&1
        #打印
        after_del_cnt=`$redis_cli -c -h $host -p $port info Keyspace|grep -v Keyspace|awk -F, '{print $1}'|awk -F: '{print $2}'|awk -F= '{print $2}'`
        echo "删除之前keys数目是${befer_del_cnt}"
        echo "删除之后keys数目是${after_del_cnt}"
        echo "删除keys数目是${key_num}"
done
echo "删除的keys总数是$sum"

可以根据实际需求,在脚本里添加sleep,删除一部分sleep一会,再接着执行,由于各个公司管理平台不同,脚本可能需要修改部分内容,可以根据思路实现自己的一套脚本

redis 模糊删除key的更多相关文章

  1. Redis模式匹配删除key

    Redis keys命令支持模式匹配,但是del命令不支持模式匹配,有时候需要根据一定的模式来模糊删除key,这时只能结合shell命令来完成了. 具体命令是: redis-cli KEYS &quo ...

  2. Redis批量删除KEY的方法

    Redis 中有删除单个 Key 的指令 DEL,但好像没有批量删除 Key 的指令,不过我们可以借助 Linux 的 xargs 指令来完成这个动作. 代码如下: redis-cli keys “* ...

  3. redis批量删除key 远程批量删除key

    一.遇到的问题 在开发的过程中,经常会遇到要批量删除某种规则的key,如缓存的课程数据“course-课程uid”,其中课程uid是变量,我们需要删除"course-*"这一类的数 ...

  4. redis 模糊删除实现

    redis 没有直接提供模糊删除的实现,我们可以根据现有的指令进行组合实现: import java.util.Arrays; import java.util.Set; import javax.a ...

  5. redis scan删除key的方法封装

    /** * @desc 迭代式的删除redis key * 用法: * $redis = BaseService::S()->getRedisConfig(\Yii::$app->redi ...

  6. Redis批量删除key的小技巧,你知道吗?

    在使用redis的过程中,经常会遇到要批量删除某种规则的key,但是redis提供了批量查询一类key的命令keys或scan,没有提供批量删除某种规则key的命令,怎么办?看完本文即可,哈哈. 本文 ...

  7. redis批量删除key

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #fffff ...

  8. redis 批量删除key

    redis-cli -h -p keys -p del s

  9. redis批量删除key 命令

    redis-cli -n 数据库编号 -a 密码 keys "过滤条件" | xargs redis-cli -n 数据库编号 -a 密码 del Demo: redis-cli ...

随机推荐

  1. 学习笔记CB007:分词、命名实体识别、词性标注、句法分析树

    中文分词把文本切分成词语,还可以反过来,把该拼一起的词再拼到一起,找到命名实体. 概率图模型条件随机场适用观测值条件下决定随机变量有有限个取值情况.给定观察序列X,某个特定标记序列Y概率,指数函数 e ...

  2. Jboss安装配置以及相关的问题

    下载地址:(目前最新版本是jboss-as-7.1.1.Final) http://download.jboss.org/jbossas/7.1/jboss-as-7.1.1.Final/jboss- ...

  3. Windows 10的最新版1803版本ISO下载

    Windows 10推出已经有几年时间了,笔者一直在用这个新版本.据说Windows 10以后只会推出新的更新,而不会有新的操作系统推出,所以Windows 10的更新就显得重要了.这次给大家推荐一个 ...

  4. 在CentOS 7上安装Nginx

    本教程中的步骤要求用户拥有root权限 第一步 - 添加Nginx存储库要添加CentOS 7 EPEL仓库,请打开终端并使用以下命令: sudo yum install epel-release第二 ...

  5. ROS tf

    一.节点中使用(cpp,python) 1. ros wiki 提供的tutorials 2. https://blog.csdn.net/start_from_scratch/article/det ...

  6. 在已安装64位oracle的服务器安装32位客户端

    应用场景:服务器操作系统是win2012 64位,原先安装了64位oracle12,后来系统增加导入excel的功能,网站必须启用32位兼容模式,这时候发现原有的页面打不开,提示: 试图加载格式不正确 ...

  7. Zuul转发请求时HttpHostConnectException can't cast to ZuulException问题解决方法

    看了一下github上的issue,这应该是一个bug.说是已经在zuul 2.0.1.RELEASE中处理了,但是我用的SpringBoot2.0.4.RELEASE中仍然有问题. 处理方案如下: ...

  8. sed命令的基本使用方法

    sed命令 stream editor,用程序的方式编辑文本.基本上是玩正则模式匹配. 用s命令替换 $ sed "s/my/Hao Chen's/g" pets.txt 单引号去 ...

  9. python爬虫学习笔记(一)——环境配置(windows系统)

    在进行python爬虫学习前,需要进行如下准备工作: python3+pip官方配置 1.Anaconda(推荐,包括python和相关库)   [推荐地址:清华镜像] https://mirrors ...

  10. HTML 理解标签 - 帧

    帧 : frame(已弃用) 是一个HTML元素,它定义了可以显示另一个HTML文档的特定区域.一个框架应该用在一个框架内 <frameset> iframe 表示嵌套的浏览上下文,有效地 ...