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 *
輸入完並回車等了一段時間, 屏幕上才開始輸出結果
使用scan命令代替KEYS
ps: scan命令需要保證redis的版本在2.8以上
SCAN 命令用於迭代當前數據庫中的數據庫鍵
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
個人覺得SCAN的COUNT參數的設置是比較重要的, 大了, 會導致單次命令執行時間太長; 小了, 會導致需要迭代的次數太多, 導致耗時太久;
下面先通過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