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

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM