开发者

shell脚本批量导出redis key-value方式

目录
  • 1 背景
  • 2 详细步骤
    • 2.1 本地docker启动Redis
    • 2.2 shell批量导出脚本
  • 3 附录
    • 总结

      1 背景

      需求:工作中需要导出线上redis数据,但需避免使用keys命令全量扫描,导致瞬间响应卡顿,从而引发超时等问题

      方法:最安全的方式是通过dump.rdb备份文件,在本地redis实例上android恢复,然后执行shell脚本,使用scan渐进扫描批量导出key-value。

      2 详细步骤

      2.1 本地docker启动redis

      本地通过docker-compose创建redis实例,并挂载配置文件和数据目录

      • docker-compose.yml
      version: '3'
      services:
        redis:
          image: redis
          container_name: redis
          restart: always
          command: redis-server /etc/redis/redis.conf
          ports:
            - 46379:6379
          environment:
            TZ: Asia/Shanghai
            LANG: en_US.UTF-8
          volumes:
            - ./mnt/conf/redis.conf:/etc/redis/redis.conf:rw
            - ./mnt/data:/data:rw
      
      • 在宿主机创建配置文件

      指定dump恢复目录及文件,和redis实例密码

      mkdir -p ./mnt/conf
      vim ./mnt/conf/redis.conf
      
      requirepass GSef7NOoIH5R
      dbfilename dump.rdb
      dir /data
      
      • 将dump.rdb备份文件放在宿主机./mnt/conf/data下,启动redis
      docker-compose up -d
      
      • 通过日志查看备份恢复进度
      docker logs -f redis
      
      • 验证恢复情况
      # 进入容器
      docker exec -it redis bash
      
      # 认证
      auth GSef7NOoIH5R
      
      # 查询key数量
      dbsize
      

      2.2 shell批量导出脚本

      • 进入容器
      docker exec -it redis bash
      
      • 为便于后续操作,在容器安装vim(也可在宿主机挂载目录创建shell脚本)
      # 换源并安装vim
      sed -i 's/deb.Debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list  \
          && apt update -y \
          && apt-get install -y vim
      
      # 解决vim中文乱码
      echo -e "syntax on \nset termencoding=utf-8 \nset encoding=utf8 \nset fileencodings=utf8,ucs-bom,gbkwww.devze.com,cp936,gb2312,gb18030" >> ~/.vimrc
      
      • 创建shell脚本

      使用的scan命令渐进遍历,相对于keys命令全量遍历速度慢些,但胜在安全,对redis的负载低。其中:

      • 可通过CNT参数设定迭代元素的数量来以控制redis负载
      • 获取value值时,通过INTERVAL调整redis-cli的执行间隔,来控制redis负载
      vim redis_export.sh
      
      #!/bin/bash
      REDIS_HOST=localhost
      REDIS_PORT=6379
      REDIS_PASSWORD=GSef7NOoIH5R
      CNT=1000
      
      KEY_NAME=vc_*
      KEY_FILE=key_list.txt
      VALUE_FILE=value_list.txt
      RESULT_FILE=kv_result.txt
      INTERVAL=0.01
      
      redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD scan 0 match "$KEY_NAME"  count $CNT 2>/dev/null> scan_tmp_result
      new_cursor=`sed -n '1p' scan_tmp_result`
      sed -n fSOiqukTd'2,$p' scan_tmp_result > $KEY_FILE
      
      while [ $new_cursor -ne 0 ]
      do
        redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD scan $new_cursor match "$KEY_NAME" count $CNT 2>/dev/null> scan_tmp_result
        new_cursor=`sed -n '1p' scan_tmp_result`
        echo `cat $KEY_FILE |wc -l`
        sed -n '2,$p' scan_tmp_result >> $KEY_FILE
      done
      TOTAL=`cat $KEY_FILE |wc -l`
      echo $TOTAL
      
      > $VALUE_FILE
      i=0
      for key in `cat $KEY_FILE`
      do
          i=$(($i+1))
          if [[ ${i}%1000 -eq 0 || ${i} -eq $total ]]; fSOiqukTdthen
      	    echo "$i / $TOTAL"
          fi
       js   echo "GET $key" | redis-cli $INTERVAL -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD 2>/dev/null >> $VALUE_FILE
      done
      paste $KEY_FILE $VALUE_FILE > $RESULT_FILE
      rm -f scan_tmp_result $VALUE_FILE $KEY_FILE
      
      • 运行脚本
      bash ./redis_export.sh
      

      3 附录

      记录下实践时的其它方法/功能:

      • scan扫描不指定游标,相比keys pattern模式不会长时间阻塞redis。(可通过-i调整执行间隔控制负载)
      redis-cli  -a GSef7NOoIH5R --scan --pattern "vc_*">/tmp/redis.log
      
      • keys全量扫描(慎用)
      echo "KEYS vc_*" | redis-cli -a GSef7NOoIH5R >/tmp/redis.log
      

      总结

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新数据库

      数据库排行榜