关于Redis bigkeys命令会阻塞问题的解决

目录
  • 前言
  • 一、 顺丰高级开发工程师在线执行了 Redis 危险命令导致某公司损失 400 万
  • 二、测试一下1000万数据的性能
    • 1、编写脚本文件
    • 2、写入Redis1000万数据
    • 3、通过keys * 查看1000万数据
    • 4、通过配置文件禁止keys *的使用
  • 三、使用scan替代keys *
  • 四、拒绝bigkey
    • 1、阿里云Redis开发规范
    • 2、出现bigkey时如何删除?
    • 3、bigkey会造成哪些问题?
    • 4、如何发现bigkey?

前言

今天分享一次Redis引发的线上事故,避免再次踩雷,实现快速入门,丰富个人简历,提高面试level,给自己增加一点谈资,秒变面试小达人,BAT不是梦。

一、 顺丰高级开发工程师在线执行了 Redis 危险命令导致某公司损失 400 万

一个命令损失数百万,这,需要赔偿吗?

代码不规范,同事两行泪,撸码需谨慎!

处于好奇考虑,我来测试一下,这到底是什么问题?

二、测试一下1000万数据的性能

1、编写脚本文件

写入1000万数据。

for((i=1;i<=10000000;i++)); do echo "set k$i 哪吒编程$i" >> /tmp/test1.txt;done;

通过/tmp/test1.txt查看一下是否写入成功。

2、写入Redis1000万数据

cat /tmp/test1.txt | redis-cli -a 111111 --pipe

3、通过keys * 查看1000万数据

4、通过配置文件禁止keys *的使用

在redis.conf文件中配置security:

  rename- command keys ""
  rename- command flushdb ""
  rename- command flushall ""

三、使用scan替代keys *

Redis Scan 命令用于迭代数据库中的数据库键。

SCAN 命令是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。

SCAN 返回一个包含两个元素的数组, 第一个元素是用于进行下一次迭代的新游标, 而第二个元素则是一个数组, 这个数组中包含了所有被迭代的元素。如果新游标返回 0 表示迭代已结束。

scan语法:

SCAN cursor [MATCH pattern] [COUNT count]

四、拒绝bigkey

1、阿里云Redis开发规范

阿里云Redis开发规范中明确规定“拒绝bigkey(防止网卡流量、慢查询)”

String类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。

2、出现bigkey时如何删除?

  1. String类型的用del删除。
  2. 其它类型使用hscan、sscan、zscan方式渐进式删除,同时要避免bigkey过期时间自动删除问题,因为它会造成主线程阻塞。

Hash 删除: hscan+hdel

public void delBigHash(String host, int port, String password, String bigHashKey) {
    Jedis jedis = new Jedis(host, port);
    if (password != null && !"".equals(password)) {
        jedis.auth(password);
    }
    ScanParams scanParams = new ScanParams().count(100);
    String cursor = "0";
    do {
        ScanResult<Entry<String, String>> scanResult = jedis.hscan(bigHashKey, cursor, scanParams);
        List<Entry<String, String>> entryList = scanResult.getResult();
        if (entryList != null && !entryList.isEmpty()) {
            for (Entry<String, String> entry : entryList) {
                jedis.hdel(bigHashKey, entry.getKey());
            }
        }
        cursor = scanResult.getStringCursor();
    } while (!"0".equals(cursor));

    //删除 bigkey
    jedis.del(bigHashKey);
}

3、bigkey会造成哪些问题?

  1. 内存不均,集群迁移困难;
  2. 超时删除,阻塞线程;
  3. 网络流量阻塞;

4、如何发现bigkey?

(1)通过redis-cli --bigkeys查找。

(2)计算每个键值的字节数,通过memory usage key查找

到此这篇关于关于Redis bigkeys命令会阻塞问题的解决的文章就介绍到这了,更多相关Redis bigkeys命令阻塞内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • redis的bigkey扫描脚本深入介绍

    前言 众所周知,redis里面的大key存在是非常危险的一件事情.因为最近的工作转移到中间件相关的工作,因此关注了一下bigkey的扫描方法.首先介绍一下阿里云提供的扫描脚本: 具体可见:https://yq.aliyun.com/articles/117042?t=t1 我对这个脚本进行了一个压力测试,在redis的内存为15G,key的数量为2KW,ops为40K到80K之间,在这种情况下,阿里云的脚本完全不能跑成功(估计跑出来的时间以天为单位),主要原因是每确认一个key的情况,就需要与r

  • 关于Redis bigkeys命令会阻塞问题的解决

    目录 前言 一. 顺丰高级开发工程师在线执行了 Redis 危险命令导致某公司损失 400 万 二.测试一下1000万数据的性能 1.编写脚本文件 2.写入Redis1000万数据 3.通过keys * 查看1000万数据 4.通过配置文件禁止keys *的使用 三.使用scan替代keys * 四.拒绝bigkey 1.阿里云Redis开发规范 2.出现bigkey时如何删除? 3.bigkey会造成哪些问题? 4.如何发现bigkey? 前言 今天分享一次Redis引发的线上事故,避免再次踩

  • redis实现队列的阻塞、延时、发布和订阅

    目录 普通队列 阻塞队列 发布订阅模式 延时队列和优先级队列 应用场景 Redis不仅可作为缓存服务器,还可以用作消息队列.它的列表类型天生支持用作消息队列.如下图所示: 由于Redis的列表是使用双向链表实现的,保存了头节点和尾节点,所以在列表的头部和尾部两边插入或获取元素都是非常快的,时间复杂度为O(1). 普通队列 可以直接使用Redis的list数据类型实现消息队列,只需简单的两个指令lpush和rpop或者rpush和lpop. lpush+rpop:左进右出的队列 rpush+lpo

  • 详解Redis SCAN命令实现有限保证的原理

    SCAN命令可以为用户保证:从完整遍历开始直到完整遍历结束期间,一直存在于数据集内的所有元素都会被完整遍历返回,但是同一个元素可能会被返回多次.如果一个元素是在迭代过程中被添加到数据集的,又或者是在迭代过程中从数据集中被删除的,那么这个元素可能会被返回,也可能不会返回. 这是如何实现的呢,先从Redis中的字典dict开始.Redis的数据库是使用dict作为底层实现的. 字典数据类型 Redis中的字典由dict.h/dict结构表示: typedef struct dict { dictTy

  • redis常用命令整理

    一.key 相关: (1)redis允许模糊查询 key(keys *) 有3个通配符 *.?.[] (2)randomkey:返回随机key (3)type key:返回key存储的类型 (4)exists key:判断某个key是否存在 (5)del key:删除key FLUSHALL: 删除所有key(慎用) 二.数据操作: Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及 zset(sorted set:有序集合). 1.stri

  • redis scan命令导致redis连接耗尽,线程上锁的解决

    使用redis scan方法无法获取connection,导致线程锁死. 0.关键字 redis springboot redistemplate scan try-with-resource 1.异常现象 应用部署后,功能正常使用,但约数小时左右,部分功能接口异常,接口请求无响应. 2.异常排查 查看堆栈信息,jstask pid.首先找到java进程pid:输出堆栈信息至log文件,jstask 30 > stask.log,看到与redis相关的日志,线程状态为waiting. "p

  • PHP操作Redis常用命令的实例详解

    redis常用命令有: 1.连接操作命令: 2.持久化命令: 3.远程服务控制命令: 4.对value操作命令:5.string命令: 6.list命令: 7.set命令: 8.hash命令等等. Redis 常用命令 登录 redis-cli -p 5566 -a password 检查key是否存在 EXISTS key 搜索某关键字 KSYS *4 返回一个Key所影响的vsl的类型 TYPE key 下面通过代码看下PHP操作Redis命令,代码如下所示: //连接本地的 Redis 服

  • Redis exists命令bug分析(案例详解)

    目录 1.复现条件版本: 2.源码分析 3.问题解决 本文基于社区版Redis 4.0.8 1.复现条件版本: 社区版Redis 4.0.10以下版本 使用场景:开启读写分离的主从架构或者集群架构(master只负责写流量,slave负责读流量) 案例: # 写入一条带过期时间10s的key 10.90.73.147:12345> set luxiu1 1 ex 10 OK 10.90.73.147:12345> get luxiu1 "1" 10.90.73.147:12

  • Redis使用命令行与多数据库配置

    一.Redis发送命令的两种方式 redis-cli -h localhost -p 6379redis-cli ping 返回pong 证明正常 二.命令返回值 1.状态回复,如ping命令 2.错误回复,如随便输入任意命令 3.整数回复,如某些命令会返回整数,incr(增加),decr(减少),dbsize(返回当前有多少个key) 4.字符串回复,如get命令,以双引号包裹,当请求的key不存在会得到一个空结果,返回(nil) 5.多行字符串回复,如keys *,返回所以key的名称 三.

  • 详解redis脚本命令执行问题(redis.call)

    1.redis-cli命令行中执行: # 调用redis命令设置缓存 # 不传参数 eval "return redis.call('set', 'name1', 'Tom')" 0 # 传入1个值参数 eval "return redis.call('set', 'name2', ARGV[1])" 0 "Tom" # 传入1个键名参数和1个值参数 eval "return redis.call('set', KEYS[1], ARG

  • Redis keys命令的具体使用

    keys命令: DEL KEY:该命令用于在key存在时删除key DUMP KEY:序列化给定key,并返回被序列化的值 序列化:把对象转化为可传输的字节的序列过程称为序列化 反序列化:把字节序列还原为对象的过程称为反序列化 为什么需要序列化? 序列化的最终目的是为了对象可以跨平台传输,和进行网络传输.而我们进行跨平台存储和网络传输的方式就是IO,而IO支持的数据格式就是字节数组. 因为我们单方面的只把对象转成字节数组还不行,因为没有规则的字节数组我们是没办法把对象的本来面目还原回来的,所以我

随机推荐