• redis-避免生产环境使用keys命令


    redis作为内存数据库, 有着很高的性能, Redis能读的速度是110000次/s, 写的速度是81000次/s;

    除了进行持久化操作时, redis采用的是单线程架构, 所以如果我们在开发中不恰当的使用一些命命令, 就很有可能导致意料之外的结果, 比如如果redis中有千万级别的key, 而我们在程序中使用keys pattern命令来匹配相关的键, 那么大概率会导致redis的阻塞设置宕机;

    测环境中模拟生产环境, 快速生成百万级别的key-value键值对

    注意, 下面的命令仅用于测试, 不要再生产环境使用

    127.0.0.1:6379> debug populate 2000000
    OK
    (1.29s)
    
    127.0.0.1:6379> DBSIZE
    (integer) 2000001
    

    通过上面的命令, 在redis中生成了200万个key, 竟然是测试, 那么执行下keys *也无妨, 执行完后, 通过slowlog get 5来查看最近5条执行速度慢的命令, 因为redis是单线程的, 所以这命令会导致redis阻塞, 图中也可看出, KEYS *输入完并回车等了一段时间, 屏幕上才开始输出结果

    1

    image

    使用scan命令代替KEYS

    ps: scan命令需要保证redis的版本在2.8以上

    SCAN 命令用于迭代当前数据库中的数据库键

    SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

    个人觉得SCANCOUNT参数的设置是比较重要的, 大了, 会导致单次命令执行时间太长; 小了, 会导致需要迭代的次数太多, 导致耗时太久;

    下面先通过slowlog reset清空慢日志记录, 然后执行SCAN 0 MATCH 'key:2000*' COUNT 50000去匹配key, 然后再去查看慢执行日志

    127.0.0.1:6379> SLOWLOG reset
    OK
    127.0.0.1:6379> SCAN 0 MATCH 'key:2000*' COUNT 50000
    1) "1623648"
    2) 1) "key:200004"
    127.0.0.1:6379> SLOWLOG get 1
    1) 1) (integer) 18
       2) (integer) 1600503739
       3) (integer) 35363
       4) 1) "SCAN"
          2) "0"
          3) "MATCH"
          4) "key:2000*"
          5) "COUNT"
          6) "50000"
       5) "127.0.0.1:42434"
       6) ""
    

    可以看到, 设置了COUNT为50000时, slowlog记录了这条命令, 那么再把COUNT调小进行测试, 在我的电脑上的将COUNT参数设置为12500时, SCAN命令不会出现在slowlog中

    C#使用StackExchange.Redis通过SCAN命令来模式匹配KEY

    • 建立控制台项目
    • 安装nuget包StackExchange.Redis
    • 代码:
    class Program
    {
        static void Main(string[] args)
        {
            var redis = ConnectionMultiplexer.Connect("localhost, password=123456789");
            var db = redis.GetDatabase();
            var server = redis.GetServer(redis.GetEndPoints(true).FirstOrDefault());
    
            var sw = new Stopwatch();
            sw.Start();
            var keys = server.Keys(pattern: "key:2000*", pageSize: 5000, database: db.Database);
            sw.Stop();
            Console.WriteLine($"time used: {sw.ElapsedMilliseconds}ms, matched keys: {keys.Count()}");
    
            Console.ReadLine();
        }
    }
    

    执行结果

    time used: 1ms, matched keys: 111

    注意下: var keys = server.Keys(pattern: "key:2000*", pageSize: 5000, database: db.Database); 这句, 这个方法的pageSize参数, 就对应了SCAN命令的COUNT参数, 我这边测试下来, 设置为5000时命令不会出现在slowlog的记录中

    总结

    redis中如果要通过模式匹配的方式来查询某个字符串, 有KEYS命令和SCAN命令, 这两个命令的时间复杂度都是O(N), 而redis又是单线程的设计, 使用不当会导致阻塞严重的话甚至宕机, 所以生产环境如果redis中key的数量在百万或千万级别(如果用户量很大的话, 这个量级应该很容易达到的), 要避免使用KEYS命令, 谨慎使用SCAN命令; 对于KEYS命令, 生产环境中, 它是比较危险的一个命令, 可以将它重命名, 使其无法轻易使用rename-command KEYS eIiGXix4A2DreBBsQwY6YHkidcDjoYA2DreBBsQ

    参考

  • 相关阅读:
    Elastic Search的学习
    数据分析相关
    爬虫相关
    Git 知识总结
    运维开发
    Flask
    Linux入门
    MYSQL, REDIS 等数据库的介绍
    Django的学习之路
    逆向工具Frida 环境搭建
  • 原文地址:https://www.cnblogs.com/Laggage/p/13696895.html
Copyright © 2020-2023  润新知