jedis使用scan替換keys

keys命令和scan命令區別

KEYS命令是將redis中所有的key與KEYS參數一一匹配,時間複雜度是O(N),耗費時間很少,使用也非常簡單,一次性返回所有匹配的key,會阻塞服務,對服務器的性能影響較大,一般產線會禁止使用,該命令的使用方式是:KEYS PATTERN
SCAN命令是將所有的key分頁處理,每次處理的條數通過參數傳入,只返回少量元素處理後返回一個遊標,下次請求時再攜帶該遊標,該命令初始被設置爲0時,標識服務器將開始一次新的迭代,當服務器向用戶返回值爲0的遊標時,代表迭代已結束,該命令的使用方式:SCAN cursor [MATCH pattern] [COUNT count]

命令演示

 初始化數據

set key:1 a
set key:2 b
set key:3 c
set key:4 d
set key:5 e
set key:6 f
set key:7 g
set key:8 h
set key:9 i
set key:10 j
set key:11 k
set key:12 l
set key:13 m
set test test

 keys *匹配,可以看到會匹配返回所有滿足條件的數據

LOCAL:4>keys "key:*"
 1)  "key:13"
 2)  "key:12"
 3)  "key:11"
 4)  "key:6"
 5)  "key:5"
 6)  "key:9"
 7)  "key:8"
 8)  "key:7"
 9)  "key:1"
 10)  "key:2"
 11)  "key:4"
 12)  "key:10"
 13)  "key:3"
LOCAL:4>

scan 匹配所有,先是初始化遊標爲0,然後依次返回,返回的第一個遊標爲7,下次再次從scan 7開始返回遊標0代表匹配完畢,默認COUNT爲10

LOCAL:4>scan 0
 1)  "7"
 2)    1)   "key:12"
  2)   "test"
  3)   "key:5"
  4)   "key:6"
  5)   "key:11"
  6)   "key:8"
  7)   "key:13"
  8)   "key:9"
  9)   "key:3"
  10)   "key:10"

LOCAL:4>scan 7
 1)  "0"
 2)    1)   "key:4"
  2)   "key:2"
  3)   "key:1"
  4)   "key:7"

LOCAL:4>

scan 匹配滿足條件的元素:scan 0 MATCH *key:*,先是初始化遊標爲0,然後依次返回,返回的第一個遊標爲7,下次再次從scan 7開始返回遊標0代表匹配完畢

LOCAL:4>scan 0 MATCH *key:*
 1)  "7"
 2)    1)   "key:12"
  2)   "key:5"
  3)   "key:6"
  4)   "key:11"
  5)   "key:8"
  6)   "key:13"
  7)   "key:9"
  8)   "key:3"
  9)   "key:10"

LOCAL:4>scan 7 MATCH *key:*
 1)  "0"
 2)    1)   "key:4"
  2)   "key:2"
  3)   "key:1"
  4)   "key:7"

LOCAL:4>

Scan命令的保證

SCAN命令以及其他增量式迭代命令, 在進行完整遍歷的情況下可以爲用戶帶來以下保證 :

從完整遍歷開始直到完整遍歷結束期間, 一直存在於數據集內的所有元素都會被完整遍歷返回; 這意味着, 如果有一個元素, 它從遍歷開始直到遍歷結束期間都存在於被遍歷的數據集當中, 那麼 SCAN 命令總會在某次迭代中將這個元素返回給用戶。
同樣,如果一個元素在開始遍歷之前被移出集合,並且在遍歷開始直到遍歷結束期間都沒有再加入,那麼在遍歷返回的元素集中就不會出現該元素。
然而因爲增量式命令僅僅使用遊標來記錄迭代狀態, 所以這些命令帶有以下缺點:

同一個元素可能會被返回多次。 處理重複元素的工作交由應用程序負責, 比如說, 可以考慮將迭代返回的元素僅僅用於可以安全地重複執行多次的操作上。
如果一個元素是在迭代過程中被添加到數據集的, 又或者是在迭代過程中從數據集中被刪除的, 那麼這個元素可能會被返回, 也可能不會。

SCAN命令每次執行返回的元素數量

SCAN增量式迭代命令並不保證每次執行都返回某個給定數量的元素,甚至可能會返回零個元素, 但只要命令返回的遊標不是 0 , 應用程序就不應該將迭代視作結束。

不過命令返回的元素數量總是符合一定規則的, 對於一個大數據集來說, 增量式迭代命令每次最多可能會返回數十個元素;而對於一個足夠小的數據集來說, 如果這個數據集的底層表示爲編碼數據結構(小的sets, hashes and sorted sets), 那麼增量迭代命令將在一次調用中返回數據集中的所有元素。

如果需要的話,用戶可以通過增量式迭代命令提供的COUNT選項來指定每次迭代返回元素的最大值。

COUNT選項

對於增量式迭代命令不保證每次迭代所返回的元素數量,我們可以使用COUNT選項, 對命令的行爲進行一定程度上的調整。COUNT 選項的作用就是讓用戶告知迭代命令, 在每次迭代中應該從數據集裏返回多少元素。使用COUNT 選項對於對增量式迭代命令相當於一種提示, 大多數情況下這種提示都比較有效的控制了返回值的數量。

COUNT 參數的默認值爲 10 。
數據集比較大時,如果沒有使用MATCH 選項, 那麼命令返回的元素數量通常和 COUNT 選項指定的一樣, 或者比 COUNT 選項指定的數量稍多一些。
在迭代一個編碼爲整數集合(intset,一個只由整數值構成的小集合)、 或者編碼爲壓縮列表(ziplist,由不同值構成的一個小哈希或者一個小有序集合)時, 增量式迭代命令通常會無視 COUNT 選項指定的值, 在第一次迭代就將數據集包含的所有元素都返回給用戶。
注意: **並非每次迭代都要使用相同的 COUNT 值 **,用戶可以在每次迭代中按自己的需要隨意改變 COUNT 值, 只要記得將上次迭代返回的遊標用到下次迭代裏面就可以了。

MATCH 選項

類似於KEYS 命令,增量式迭代命令通過給定 MATCH 參數的方式實現了通過提供一個 glob 風格的模式參數, 讓命令只返回和給定模式相匹配的元素

返回值

SCAN, SSCAN, HSCAN 和 ZSCAN 命令都返回一個包含兩個元素的 multi-bulk 回覆: 回覆的第一個元素是字符串表示的無符號 64 位整數(遊標), 回覆的第二個元素是另一個 multi-bulk 回覆, 包含了本次被迭代的元素。

SCAN 命令返回的每個元素都是一個key。
SSCAN 命令返回的每個元素都是一個集合成員。
HSCAN 命令返回的每個元素都是一個鍵值對,一個鍵值對由一個鍵和一個值組成。
ZSCAN命令返回的每個元素都是一個有序集合元素,一個有序集合元素由一個成員(member)和一個分值(score)組成。

scala測試代碼

object JedisTest {
  @throws[Exception]
  def main(args: Array[String]): Unit = {

    var jedis:Jedis = null
    try {
      val jedisPool = new JedisPool("127.0.0.1")
      jedis =jedisPool.getResource
      val key = "aos:prod:survey:signup:"
//      val key = "aos:prod:survey:signup:6:1079029543"
      val scanParams = new ScanParams().count(100).`match`("\\*")
      var cur = redis.clients.jedis.ScanParams.SCAN_POINTER_START
      var cycleIsFinished = false
      while ( !cycleIsFinished) {
        val scanResult = jedis.hscan(key, cur, scanParams)
        cur = scanResult.getCursor
        val result = scanResult.getResult
        println(result)
        //do whatever with the key-value pairs in result
//        cur = scanResult.getCursor
        if (cur == "0") cycleIsFinished = true
      }
    } catch {
      case e: Exception =>
        e.printStackTrace()
    } finally if (null != jedis) jedis.close()
  }
}

ref: http://www.redis.cn/commands/scan.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章