一. 問題情境
Redis 作為當前最流行的記憶體型 NoSQL 資料庫,被許多公司所使用,作為分布式緩衝。我們在實際使用中一般都會為 key 帶上指定的首碼或者其他定義的格式。當由於我們程式出現bug,造成 redis 裡面的儲存的值,與我們預期的不一致時,我們可以通過查詢指定格式的 key,來定位到我們具體的出現問題的key,從而方便我們解決問題。
二. 解決辦法1.Keys 命令
Keys 命令用於尋找所有符合給定模式 pattern 的 key 。要求 Redis 版本大於 1.0.0。keys在查詢大數量key時,會長時間阻塞Redis,由於Redis是單線程的,這就是一個突出的問題,需要注意。
2.Scan 命令
Scan 命令相對於 Keys 命令來說,優點就是不會阻塞伺服器。要求 Redis 版本大於 2.8。
三. 代碼實現
這裡採用的Redis驅動是 StackExchange.Redis。
在 StackExchange.Redis 裡封裝 Redis 命令時分為了兩種,一種是針對於叢集的命令,一種是針對於單個Redis伺服器的命令,Keys 和 Scan 命令便是後者,我們在使用的時候必須在單獨的伺服器上執行。
Keys 和 Scan 命令都支援模糊查詢,這裡介紹三種匹配符:
- * 表示可以匹配多個任一字元
- ? 表示可以匹配單個任一字元
- [] 表示可以匹配指定範圍內的字元
因為我們的key可能分布在叢集內多個Redis伺服器上,所以我們需要在每台伺服器上都執行命令。我們可以通過 ConnectionMultiplexer.GetEndPoints()
方法來擷取所有的終結點資訊。
在 StackExchange.Redis 對於 keys 和 scan 命令統一封裝為了 IServer.Keys()
方法,它會自動根據Redis伺服器版本來決定使用keys命令還是scan命令。
為了方便測試,我在 Redis 裡面準備了四個以 test
為首碼的key,放在序號為1的db裡面:
1.遍曆所有首碼為 test 的key 代碼如下:
static async Task Main(string[] args){ //建立串連 var conn = await ConnectionMultiplexer.ConnectAsync("192.168.10.110"); //擷取db var db = conn.GetDatabase(1); //遍曆叢集內伺服器 foreach (var endPoint in conn.GetEndPoints()) { //擷取指定伺服器 var server = conn.GetServer(endPoint); //在指定伺服器上使用 keys 或者 scan 命令來遍曆key foreach (var key in server.Keys(1,"test.*")) { //擷取key對於的值 var val = db.StringGet(key); Console.WriteLine($"key: {key}, value: {val}"); } }}
執行結果:
2.[]的用法
假設我要遍曆 key為 test.1-test.3
的資料,可以這樣寫:
static async Task Main(string[] args){ //建立串連 var conn = await ConnectionMultiplexer.ConnectAsync("192.168.10.110"); //擷取db var db = conn.GetDatabase(1); //遍曆叢集內伺服器 foreach (var endPoint in conn.GetEndPoints()) { //擷取指定伺服器 var server = conn.GetServer(endPoint); //在指定伺服器上使用 keys 或者 scan 命令來遍曆key foreach (var key in server.Keys(1,"test.[1-3]")) { //擷取key對於的值 var val = db.StringGet(key); Console.WriteLine($"key: {key}, value: {val}"); } }}
執行結果:
假設我要遍曆 key為 test.1和test.4 的資料,可以這樣寫:
static async Task Main(string[] args){ //建立串連 var conn = await ConnectionMultiplexer.ConnectAsync("192.168.10.110"); //擷取db var db = conn.GetDatabase(1); //遍曆叢集內伺服器 foreach (var endPoint in conn.GetEndPoints()) { //擷取指定伺服器 var server = conn.GetServer(endPoint); //在指定伺服器上使用 keys 或者 scan 命令來遍曆key foreach (var key in server.Keys(1,"test.[1,4]")) { //擷取key對於的值 var val = db.StringGet(key); Console.WriteLine($"key: {key}, value: {val}"); } }}
執行結果:
好了,關於 Redis 查詢指定格式的 key 的方法就介紹到這裡了。
四. 參考資料
Where are KEYS, SCAN, FLUSHDB etc? by StackExchange.Redis