關於redis的keys命令的效能問題

2021-10-16 17:36:15 字數 3834 閱讀 3988

查詢所有符合給定模式patternkey

keys *匹配資料庫中所有key

keys h?llo匹配hellohallohxllo等。

keys h*llo匹配hlloheeeeello等。

keys h[ae]llo匹配hellohallo,但不匹配hillo

實際應用中有時候會出現需要遍歷redis中的所有鍵值的需求,比如清理沒用的鍵等等。但是keys這個命令效能真的很差,redis官方文件是這麼說的: 

keys模糊匹配,請大家在實際運用的時候忽略掉。因為keys會引發redis鎖,並且增加redis的cpu占用,情況是很惡劣的,實際應用中有時候會出現需要遍歷redis中的所有鍵值的需求,比如清理沒用的鍵等等。但是keys這個命令效能真的很差。

上面是官方文件宣告,keys命令不能用在生產的環境中,這個時候如果數量過大效率是十分低的。同時也不要用keys正則匹配,官方建議直接用集合型別。

有人說keys相當於關係性資料的庫的select *,在生產環境幾乎是要禁用的。

試想如果redis阻塞超過10秒,如果有集群的場景,可能導致集群判斷redis已經故障,從而進行故障切換;

以上的情況嚴重會導致應用程式出現雪崩的情況。

然而,網上很多都是這麼寫的redis-cli --raw keys "key字首*" | xargs redis-cli del,千萬別照炒,拿到生產環境上做實驗。(實際應用中有時候會出現需要遍歷redis中的所有鍵值的需求,比如清理沒用的鍵等等。但是keys這個命令效能真的很差)

順便普及下xargs命令,這是linux下的乙個命令 。

xargs命令是給其他命令傳遞引數的乙個過濾器,也是組合多個命令的乙個工具。它擅長將標準輸入資料轉換成命令列引數,xargs能夠處理管道或者stdin並將其轉換成特定命令的命令引數。xargs也可以將單行或多行文字輸入轉換為其他格式,例如多行變單行,單行變多行。xargs的預設命令是echo,空格是預設定界符。這意味著通過管道傳遞給xargs的輸入將會包含換行和空白,不過通過xargs的處理,換行和空白將被空格取代。xargs是構建單行命令的重要元件之一。

由於執行keys命令,redis會鎖定,如果資料龐大的話可能需要幾秒或更長,對於生產伺服器上鎖定幾秒這絕對是災難了

如果有這種需求的話可以自己對鍵值做索引,比如把各種鍵值存到不同的set裡面,分類建立索引,這樣就可以很快的得到資料,但是這樣也存在乙個明顯的缺點,就是浪費寶貴的空間,要知道這可是記憶體空間啊,所以還是要合理考慮,當然也可以想辦法,比如對於有規律的鍵值,可以儲存他們的始末值等等。

使用redis的時候要注意很多細節,當時的leader說過一句話很受啟發,雖然redis只提供了五種型別,但是用起來不一定就只有五種,比如string型別,你可以儲存任何你自己定義的型別,所以思想不能侷限,靈活的設定資料結構。還有就是雖然redis訪問很快,但是正常生產環境,redis伺服器肯定和web伺服器不是在一起,有時候甚至是在不同的地區,所以網路通訊延遲就很重要了,所以要減少訪問次數,一次訪問完成更多的工作,否則你會發現做同樣的事redis還沒有關係型資料庫快,所以redis存的時候一定要有技巧,盡可能減少訪問次數。

從redis的官方文件上看,2.8版本之後scan命令已經可用,允許使用游標從keyspace中檢索鍵。對比keys命令,雖然scan無法一次性返回所有匹配結果,但是卻規避了阻塞系統這個高風險,從而也讓一些操作可以放在主節點上執行。

需要注意的是,scan 命令是乙個基於游標的迭代器。scan 命令每次被呼叫之後, 都會向使用者返回乙個新的游標,使用者在下次迭代時需要使用這個新游標作為 scan 命令的游標引數, 以此來延續之前的迭代過程。同時,使用scan,使用者還可以使用keyname模式和count選項對命令進行調整。scan相關命令還包括sscan 命令、hscan 命令和 zscan 命令,分別用於集合、雜湊鍵及有續集等。

另一方面,使用redis的時候一定要注意控制key,對於key的命令要制定乙個完善的方案,這樣才能對redis裡面的資料可控,避免出現沒用資料長時間佔據資料庫這種情況,也可以避免上面說的這種查詢鍵值的操作。

redis從2.8版本開始支援scan命令,scan命令的基本用法如下:

scan cursor [match pattern] [count count]
127.0.0.1:6379> scan 0 match tony* 

1) "42"

2)  1) "tony25"

2) "tony2519"

3) "tony2529"

4) "tony2510"

5) "tony2523"

6) "tony255"

7) "tony2514"

8) "tony256"

9) "tony2511"

10) "tony15"

127.0.0.1:6379> scan 42 match tony* count 1000

1) "0"

2)  1) "tony3513"

2) "tony359"

3) "tony4521"

4) "tony356"

5) "tony30"

6) "tony320"

7) "tony3"

8) "tony312"

返回分為兩個部分如上面的**中, 1)代表下一次迭代的游標,2)代表本次迭代的結果集,注意如果返回游標為0就代表全部匹配完成。

因為keys命令的時間複雜度為o(n),而scan命令會將遍歷操作分解成m次,然後每次去執行,從而時間複雜度為o(1)。也解決使用keys命令遍歷大量資料而導致redis伺服器阻塞的情況。所以建議使用下邊的指令進行批量的刪除操作:

redis-cli --scan --pattern "key字首*" | xargs -l 1000 redis-cli del
因為redis是但執行緒的keys在某種情況下會阻塞。有個真實真案件小哥哥生產用keys,最終導致服務宕機。後果很嚴重,產生的經濟損失就不說了。

切記嚴重會導致程式的雪崩,刪除的時候用scan命令,看完這篇文章應該都記住了。

redis開發的建議

1、 資料分離

不要什麼都往redis中放,盡量放些qps比較高的資料,記憶體的開銷很昂貴的,可以考慮硬碟存放。

2、分業務

不同的例項單獨放這樣訪問的時候方便些,故障的時候也不會影響其他的例項。

3、壓縮

redis中有很大的單個key的值建議壓縮成二進位制存放。

4、失效時間

redis中設定key的失效時間,如果不設定會一直占用著記憶體,而且key的失效時間應該根據業務場景來設定。

5、容量

占用記憶體不要太大10-20g,其次鍵的數量控制在1千萬以內。

6、監控

運維合理的監控好資料,做好redis安全漏洞的防護和災備。

關於redis的keys命令的效能問題

keys pattern 查詢所有符合給定模式pattern的key。keys 匹配資料庫中所有key。keys h?llo匹配hello,hallo和hxllo等。keys h llo匹配hllo和heeeeello等。keys h ae llo匹配hello和hallo,但不匹配hillo。特殊...

關於redis的keys命令的效能問題

keys pattern 查詢所有符合給定模式pattern的key。keys 匹配資料庫中所有key。keys h?llo 匹配hello,hallo和hxllo等。keys h llo 匹配hllo和heeeeello等。keys h ae llo 匹配hello和hallo,但不匹配hillo...

關於redis的keys命令的效能問題

keys pattern 查詢所有符合給定模式pattern的key。keys 匹配資料庫中所有key。keys h?llo 匹配hello,hallo和hxllo等。keys h llo 匹配hllo和heeeeello等。keys h ae llo 匹配hello和hallo,但不匹配hillo...