一次线上事故,导致公司损失400万

文章讲述了由于执行Redis的危险命令导致的线上事故,强调了规范操作的重要性。介绍了RedisScan作为安全的替代方案,并讨论了处理bigkey的策略,包括避免和删除方法,以及bigkey可能带来的问题。此外,还提到了阿里云的Redis开发规范和监控bigkey的方法。
摘要由CSDN通过智能技术生成

89beb2ccec35b3dae1054849a5495b1b.png

大家好,我是树哥。最近有小伙伴因为乱执行 Redis 扫描命令,导致了一个严重的线上事故。今天分享一篇关于 Redis Scan 的文章,让大家学习一下,避免再次发生类似事件。

一、 事故背景

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

最近安全事故频发啊,前几天发生了《顺丰高级运维工程师的删库事件》,今天又看到了 PHP 工程师在线执行了 Redis 危险命令导致某公司损失 400 万。。

什么样的 Redis 命令会有如此威力,造成如此大的损失?

具体消息如下:

据云头条报道,某公司技术部发生 2 起本年度 PO 级特大事故,造成公司资金损失 400 万,原因如下:

由于 PHP 工程师直接操作上线 redis,执行 keys wxdb(此处省略)cf8 这样的命令,导致redis锁住,导致 CPU 飙升,引起所有支付链路卡住,等十几秒结束后,所有的请求流量全部挤压到了 rds 数据库中,使数据库产生了雪崩效应,发生了数据库宕机事件。

该公司表示,如再犯类似事故,将直接开除,并表示之后会逐步收回运维部各项权限。

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

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

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

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

1、编写脚本文件

写入1000万数据。

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

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

7730fc4b477c0c3b57d3349a5281cdfd.png
2、写入Redis1000万数据
cat /tmp/test1.txt | redis-cli -a 111111 --pipe
3a2730e18398ae4399f7f06d8715463e.png
3、通过keys * 查看1000万数据
b291350d0749fde094159076b8d9606d.png
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]
e281615297617e2bbe9c8d7d0d68f186.png

四、拒绝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查找。

19bfc4b7d1bac049b46c6b3665b0e6cc.png

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

78df5465a7a9205fb8243c8001a5ae6b.png

推荐阅读

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值