日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Redis 笔记(13)— scan 和 keys 寻找特定前缀key 字段(命令格式、使用示例、定位大key)

發布時間:2023/11/28 生活经验 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis 笔记(13)— scan 和 keys 寻找特定前缀key 字段(命令格式、使用示例、定位大key) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. keys

Redis 提供了一個簡單暴力的指令 keys 用來列出所有滿足特定正則字符串規則的 key

127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set wohu1104go1 1
OK
127.0.0.1:6379> set wohu1104go2 2
OK
127.0.0.1:6379> set wohu1104go3 3
OK
127.0.0.1:6379> set wohu1104go4 5
OK
127.0.0.1:6379> set wohu1104go5 5
OK
127.0.0.1:6379> set wohu1104python 1
OK
127.0.0.1:6379> set wohu1104python2 2
OK
127.0.0.1:6379> set wohu1104python3 3
OK
127.0.0.1:6379> set wohu1104python4 4
OK
127.0.0.1:6379> keys *
1) "wohu1104python4"
2) "wohu1104go3"
3) "wohu1104python3"
4) "wohu1104go1"
5) "wohu1104go4"
6) "wohu1104python2"
7) "wohu1104go2"
8) "wohu1104python"
9) "wohu1104go5"
127.0.0.1:6379> keys wohu1104go*
1) "wohu1104go3"
2) "wohu1104go1"
3) "wohu1104go4"
4) "wohu1104go2"
5) "wohu1104go5"
127.0.0.1:6379> keys wohu1104python*
1) "wohu1104python4"
2) "wohu1104python3"
3) "wohu1104python2"
4) "wohu1104python"
127.0.0.1:6379> 

這個指令使用非常簡單,提供一個簡單的正則字符串即可,但是有很明顯的兩個缺點

  1. 沒有 offset、limit 參數,一次性吐出所有滿足條件的 key,萬一實例中有幾百萬個 key 滿足條件,輸出結果很難分析。
  2. keys 算法是遍歷算法,復雜度是 O(n),如果實例中有千萬級以上的 key,這個指令就會導致 Redis 服務卡頓,所有讀寫 Redis 的其它的指令都會被延后甚至會超時報錯,因為 Redis 是單線程程序,順序執行所有指令,其它指令必須等到當前的 keys 指令執行完了才可以繼續。

2. scan

2.1 命令

scan命令是一個基于游標的迭代器,每次被調用之后, 都會向用戶返回一個新的游標, 用戶在下次迭代時需要使用這個新游標作為 scan命令的游標參數, 以此來延續之前的迭代過程。
?
scan返回一個包含兩個元素的數組, 第一個元素是用于進行下一次迭代的新游標, 而第二個元素則是一個數組, 這個數組中包含了所有被迭代的元素。如果新游標返回 0 表示迭代已結束。
?
scan 指令是一系列指令,除了可以遍歷所有的 key 之外,還可以對指定的容器集合進行遍歷。比如

  • zscan 遍歷 zset 集合元素
  • hscan 遍歷 hash 字典的元素
  • sscan 遍歷 set 集合的元素。

它們的原理同 scan 都會類似的,因為 hash 底層就是字典,set 也是一個特殊的 hash(所有的 value 指向同一個元素),zset 內部也使用了字典來存儲所有的元素內容。

scan 命令基本語法如下:

SCAN cursor [MATCH pattern] [COUNT count]
  • cursor - 游標。
  • pattern - 匹配的模式。
  • count - 指定從數據集里返回多少元素,默認值為 10 。

第一次遍歷時,cursor 值為 0,然后將返回結果中第一個整數值作為下一次遍歷的 cursor。一直遍歷到返回的 cursor 值為 0 時結束。

2.2 特點

Redis 為了解決這個 keys 性能問題,它在 2.8 版本中加入了指令—— scan。scan 相比 keys 具備有以下特點:

  • 復雜度雖然也是 O(n),但是它是通過游標分步進行的,不會阻塞線程;
  • 提供 limit 參數,可以控制每次返回結果的最大條數,limit 只是一個 hint,返回的結果可多可少;
  • keys 一樣,它也提供模式匹配功能;
  • 服務器不需要為游標保存狀態,游標的唯一狀態就是 scan 返回給客戶端的游標整數;
  • 返回的結果可能會有重復,需要客戶端去重,這點非常重要;
  • 遍歷的過程中如果有數據修改,改動后的數據能不能遍歷到是不確定的;
  • 單次返回的結果是空的并不意味著遍歷結束,而要看返回的游標值是否為零;

2.3 使用

使用下面代碼往 Redis 中添加 1000 個有相同前綴的 key

import redisclient = redis.Redis("127.0.0.1", 6379)
for i in range(1000):client.set("wohu{}".format(i), i)

假設我們要尋找 wohu520 這個 key,那么使用下面的命令,

127.0.0.1:6379> scan 0 match wohu52* count 100
1) "488"
2) 1) "wohu529"
127.0.0.1:6379> scan 488 match wohu52* count 100
1) "372"
2) 1) "wohu52"
127.0.0.1:6379> scan 372 match wohu52* count 100
1) "242"
2) 1) "wohu523"2) "wohu521"3) "wohu522"
127.0.0.1:6379> scan 242 match wohu52* count 100
1) "342"
2) (empty array)
127.0.0.1:6379> scan 342 match wohu52* count 100
1) "449"
2) (empty array)
127.0.0.1:6379> scan 449 match wohu52* count 100
1) "261"
2) 1) "wohu527"
127.0.0.1:6379> scan 261 match wohu52* count 100
1) "93"
2) 1) "wohu525"
127.0.0.1:6379> scan 93 match wohu52* count 100
1) "139"
2) 1) "wohu524"2) "wohu528"
127.0.0.1:6379> scan 139 match wohu52* count 100
1) "279"
2) (empty array)
127.0.0.1:6379> scan 279 match wohu52* count 100
1) "0"
2) 1) "wohu526"2) "wohu520"
127.0.0.1:6379> 

從上面的過程可以看到雖然提供的 limit 是 100,但是返回的結果只有幾個甚至沒有。因為這個 limit 不是限定返回結果的數量,而是限定服務器單次遍歷的字典槽位數量(約等于)。如果將 limit 設置為 10,你會發現返回結果是空的,但是游標值不為零,意味著遍歷還沒結束。

2.4 存儲結構

Redis 中所有的 key 都存儲在一個很大的字典中,是一維數組 + 二維鏈表結構,第一維數組的大小總是 2^n(n>=0),擴容一次數組大小空間加倍,也就是 n++。
?

?

scan 指令返回的游標就是第一維數組的位置索引,我們將這個位置索引稱為槽 (slot)。如果不考慮字典的擴容縮容,直接按數組下標挨個遍歷就行了。limit 參數就表示需要遍歷的槽位數,之所以返回的結果可能多可能少,是因為不是所有的槽位上都會掛接鏈表,有些槽位可能是空的,還有些槽位上掛接的鏈表上的元素可能會有多個。每一次遍歷都會將 limit 數量的槽位上掛接的所有鏈表元素進行模式匹配過濾后,一次性返回給客戶端。

3. 大 key 定位

有時候會因為業務人員使用不當,在 Redis 實例中會形成很大的對象,比如一個很大的 hash,一個很大的 zset 這都是經常出現的。這樣的對象對 Redis 的集群數據遷移帶來了很大的問題,在內存分配上,如果一個 key 太大,那么當它需要擴容時,會一次性申請更大的一塊內存,這也會導致卡頓。如果這個大 key 被刪除,內存會一次性回收,卡頓現象會再一次產生。
?
如果觀察到 Redis 的內存大起大落,這極有可能是因為大 key 導致的,這時候你就需要定位出具體是那個 key,進一步定位出具體的業務來源,然后再改進相關業務代碼設計。
?
為了避免對線上 Redis 帶來卡頓,這就要用到 scan 指令,對于掃描出來的每一個 key,使用 type 指令獲得 key 的類型,然后使用相應數據結構的 size 或者 len 方法來得到它的大小,對于每一種類型,保留大小的前 N 名作為掃描結果展示出來。
?
上面這樣的過程需要編寫腳本,比較繁瑣,不過 Redis 官方已經在 redis-cli 指令中提供了這樣的掃描功能,我們可以直接拿來即用。

redis-cli -h 127.0.0.1 -p 6379 –-bigkeys 

如果你擔心這個指令會大幅抬升 Redisops 導致線上報警,還可以增加一個休眠參數。

redis-cli -h 127.0.0.1 -p 6379 –-bigkeys -i 0.1 

上面這個指令每隔 100 條 scan 指令就會休眠 0.1s,ops 就不會劇烈抬升,但是掃描的時間會變長。
?

參考:
https://juejin.cn/book/6844733724618129422/section/6844733724710404110?

總結

以上是生活随笔為你收集整理的Redis 笔记(13)— scan 和 keys 寻找特定前缀key 字段(命令格式、使用示例、定位大key)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。