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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis进阶-如何从海量的 key 中找出特定的key列表 Scan详解

發(fā)布時(shí)間:2025/3/21 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis进阶-如何从海量的 key 中找出特定的key列表 Scan详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 需求
  • scan
  • scan基本使用
    • 批量寫入一批模擬數(shù)據(jù)
  • 字典的結(jié)構(gòu)
  • scan 遍歷順序 (高位進(jìn)位法)
  • 漸進(jìn)式 rehash
  • 更多的 scan 指令
  • 大 key 掃描 --bigkeys
  • 使用scan的注意事項(xiàng) 20201101更新


需求

假設(shè)你需要從 Redis 實(shí)例成千上萬的 key 中找出特定前綴的 key 列表來手動(dòng)處理數(shù)據(jù),可能是修改它的值,也可能是刪除 key。那該如何從海量的 key 中找出滿足特定前綴的 key 列表來?

我們可以用 keys 來列出所有滿足特定正則字符串規(guī)則的 key .

192.168.18.131:8001> set artisan 1 OK 192.168.18.131:8001> set artisan2 2 -> Redirected to slot [6066] located at 192.168.18.132:8002 OK 192.168.18.132:8002> set artisan3 3 -> Redirected to slot [1939] located at 192.168.18.131:8001 OK 192.168.18.131:8001> set artisan4 4 -> Redirected to slot [14196] located at 192.168.18.132:8005 OK 192.168.18.132:8005> set artisan5 5 -> Redirected to slot [10069] located at 192.168.18.132:8002 OK 192.168.18.132:8002> 192.168.18.132:8002> keys * 1) "artisanKey" 2) "clusterArtisan" 3) "artisan2" 4) "ar" 5) "test" 6) "artisan5" 192.168.18.132:8002> keys artisan* 1) "artisanKey" 2) "artisan2" 3) "artisan5" 192.168.18.132:8002>

我這個(gè)是集群環(huán)境,有幾個(gè)key被分到了其他的slot上去了,所以看到的數(shù)據(jù)僅僅是當(dāng)前slot的數(shù)據(jù)。

keys 優(yōu)點(diǎn)呢 ,使用簡單

當(dāng)然了,也有缺點(diǎn)

  • 一次性列出所有滿足條件的 key. keys 算法是遍歷算法,復(fù)雜度是 O(n) ,如果數(shù)據(jù)量很大,會(huì)導(dǎo)致 Redis 服務(wù)卡頓,所有讀寫 Redis 的其它的指令都會(huì)被延后甚至?xí)瑫r(shí)報(bào)錯(cuò),因?yàn)镽edis 是單線程程序,順序執(zhí)行所有指令,其它指令必須等到當(dāng)前的 keys 指令執(zhí)行完了才可以繼續(xù)。

咋辦呢? ---------------> Redis在 2.8 版本中加入了scan指令.


scan

scan 相比keys 具備有以下特點(diǎn):

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

scan基本使用

批量寫入一批模擬數(shù)據(jù)

import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig;import java.io.IOException; import java.util.HashSet; import java.util.Set;public class JedisClusterDemo {public static void main(String[] args) throws IOException {JedisPoolConfig config = new JedisPoolConfig();config.setMaxTotal(20);config.setMaxIdle(10);config.setMinIdle(5);Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();jedisClusterNode.add(new HostAndPort("192.168.18.131", 8001));jedisClusterNode.add(new HostAndPort("192.168.18.131", 8004));jedisClusterNode.add(new HostAndPort("192.168.18.132", 8002));jedisClusterNode.add(new HostAndPort("192.168.18.132", 8005));jedisClusterNode.add(new HostAndPort("192.168.18.133", 8003));jedisClusterNode.add(new HostAndPort("192.168.18.133", 8006));JedisCluster jedisCluster = null;try {//connectionTimeout:指的是連接一個(gè)url的連接等待時(shí)間//soTimeout:指的是連接上一個(gè)url,獲取response的返回等待時(shí)間jedisCluster = new JedisCluster(jedisClusterNode, 6000, 5000, 10, "artisan", config);for (int i = 0; i < 10000; i++) {jedisCluster.set("{art}:clusterArtisan:" + i, "artisanValue:" + i);}System.out.println("DONE");} catch (Exception e) {e.printStackTrace();} finally {if (jedisCluster != null)jedisCluster.close();}} }


scan 參數(shù)提供了三個(gè)參數(shù):

  • 第一個(gè)是 cursor 整數(shù)值

  • 第二個(gè)是 key 的正則模式

  • 第三個(gè)是遍歷的 limit hint。

第一次遍歷時(shí),cursor 值為 0,然后將返回結(jié)果中第一個(gè)整數(shù)值作為下一次遍歷的 cursor。一直遍歷到返回的 cursor 值為 0 時(shí)結(jié)束

192.168.18.132:8005> scan 0 match {art}:clusterArtisan:9* count 1000 1) "13848" 2) 1) "{art}:clusterArtisan:9927"2) "{art}:clusterArtisan:9660"3) "{art}:clusterArtisan:994"4) "{art}:clusterArtisan:934".................129) "{art}:clusterArtisan:9830"130) "{art}:clusterArtisan:9470" 192.168.18.132:8005>

將第一次的返回結(jié)果 13848 ,作為第二次的入?yún)?/p> 192.168.18.132:8005> scan 13848 match {art}:clusterArtisan:9* count 1000 1) "11596" 2) 1) "{art}:clusterArtisan:9347"2) "{art}:clusterArtisan:9737"3) "{art}:clusterArtisan:9943"4) "{art}:clusterArtisan:9944".................122) "{art}:clusterArtisan:9744"123) "{art}:clusterArtisan:9256" 192.168.18.132:8005>

省略過程 …

依次,獲取 ,直到cursor為0 ,遍歷結(jié)束

192.168.18.132:8005> scan 13209 match {art}:clusterArtisan:9* count 10000 1) "0" 2) 1) "{art}:clusterArtisan:927"2) "{art}:clusterArtisan:9474"3) "{art}:clusterArtisan:9685"........................424) "{art}:clusterArtisan:9424" 192.168.18.132:8005>

我們發(fā)現(xiàn)limit 是 1000,但是返回的結(jié)果并不是返回1000個(gè)。因?yàn)檫@個(gè) limit 不是限定返回結(jié)果的數(shù)量,而是限定服務(wù)器單次遍歷的字典槽位數(shù)量(約等于)。

如果將 limit 設(shè)置為 10,你會(huì)發(fā)現(xiàn)返回結(jié)果是空的,但是游標(biāo)值不為零,意味著遍歷還沒結(jié)束。

比如

192.168.18.132:8005> scan 13822 match {art}:clusterArtisan:999* count 1000 1) "13209" 2) (empty list or set) 192.168.18.132:8005>

字典的結(jié)構(gòu)

在 Redis 中所有的 key 都存儲(chǔ)在一個(gè)很大的字典中.

這個(gè)字典的結(jié)構(gòu)和 Java 中的HashMap 一樣,是一維數(shù)組 + 二維鏈表結(jié)構(gòu).

第一維數(shù)組的大小總是 2^n(n>=0),擴(kuò)容一次數(shù)組大小空間加倍,也就是 n++。

scan 指令返回的游標(biāo)就是第一維數(shù)組的位置索引,我們將這個(gè)位置索引稱為槽 (slot)。

如果不考慮字典的擴(kuò)容縮容,直接按數(shù)組下標(biāo)挨個(gè)遍歷就行了。

limit 參數(shù)就表示需要遍歷的槽位數(shù),之所以返回的結(jié)果可能多可能少,是因?yàn)椴皇撬械牟畚簧隙紩?huì)掛接鏈表,有些槽位可能是空的,還有些槽位上掛接的鏈表上的元素可能會(huì)有多個(gè)。

每一次遍歷都會(huì)將 limit數(shù)量的槽位上掛接的所有鏈表元素進(jìn)行模式匹配過濾后,一次性返回給客戶端。


scan 遍歷順序 (高位進(jìn)位法)

scan 的遍歷順序非常特別。它不是從第一維數(shù)組的第 0 位一直遍歷到末尾,而是采用了高位進(jìn)位加法來遍歷。之所以使用這樣特殊的方式進(jìn)行遍歷,是考慮到字典的擴(kuò)容和縮容時(shí)避免槽位的遍歷重復(fù)和遺漏.

高位進(jìn)位法從左邊加,進(jìn)位往右邊移動(dòng),同普通加法正好相反。但是最終它們都會(huì)遍歷所有的槽位并且沒有重復(fù)。


漸進(jìn)式 rehash

Java 的 HashMap 在擴(kuò)容時(shí)會(huì)一次性將舊數(shù)組下掛接的元素全部轉(zhuǎn)移到新數(shù)組下面。

如果 HashMap 中元素特別多,線程就會(huì)出現(xiàn)卡頓現(xiàn)象。Redis 為了解決這個(gè)問題,它采用漸進(jìn)式 rehash。

它會(huì)同時(shí)保留舊數(shù)組和新數(shù)組,然后在定時(shí)任務(wù)中以及后續(xù)對 hash 的指令操作中漸漸地將舊數(shù)組中掛接的元素遷移到新數(shù)組上。這意味著要操作處于 rehash 中的字典,需要同時(shí)訪問新舊兩個(gè)數(shù)組結(jié)構(gòu)。如果在舊數(shù)組下面找不到元素,還需要去新數(shù)組下面去尋找。

scan 也需要考慮這個(gè)問題,對與 rehash 中的字典,它需要同時(shí)掃描新舊槽位,然后將結(jié)果融合后返回給客戶端。


更多的 scan 指令

scan 指令是一系列指令,除了可以遍歷所有的 key 之外,還可以對指定的容器集合進(jìn)行遍歷。

比如 zscan 遍歷 zset 集合元素,hscan 遍歷 hash 字典的元素、sscan 遍歷 set 集
合的元素。

它們的原理同 scan 都會(huì)類似的,因?yàn)?hash 底層就是字典,set 也是一個(gè)特殊的
hash(所有的 value 指向同一個(gè)元素),zset 內(nèi)部也使用了字典來存儲(chǔ)所有的元素內(nèi)容.


大 key 掃描 --bigkeys

[redis@artisan redis-5.0.3]$ ./bin/redis-cli -c -h 192.168.18.131 -p 8001 -a artisan --bigkeys Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.# Scanning the entire keyspace to find biggest keys as well as # average sizes per key type. You can use -i 0.1 to sleep 0.1 sec # per 100 SCAN commands (not usually needed).[00.00%] Biggest string found so far 'artisan3' with 1 bytes-------- summary -------Sampled 2 keys in the keyspace! Total key length in bytes is 15 (avg len 7.50)Biggest string found 'artisan3' has 1 bytes2 strings with 2 bytes (100.00% of keys, avg size 1.00) 0 lists with 0 items (00.00% of keys, avg size 0.00) 0 sets with 0 members (00.00% of keys, avg size 0.00) 0 hashs with 0 fields (00.00% of keys, avg size 0.00) 0 zsets with 0 members (00.00% of keys, avg size 0.00) 0 streams with 0 entries (00.00% of keys, avg size 0.00) [redis@artisan redis-5.0.3]$

如果你擔(dān)心這個(gè)指令會(huì)大幅抬升 Redis 的 ops 導(dǎo)致線上報(bào)警,還可以增加一個(gè)休眠參數(shù)。

--bigkeys -i 0.1

上面這個(gè)指令每隔 100 條 scan 指令就會(huì)休眠 0.1s,ops 就不會(huì)劇烈抬升,但是掃描的時(shí)間會(huì)變長.

[redis@artisan redis-5.0.3]$ ./bin/redis-cli -c -h 192.168.18.131 -p 8001 -a artisan --bigkeys -i 0.1

使用scan的注意事項(xiàng) 20201101更新

如果在scan的過程中如果有鍵的變化(增加、 刪除、 修改) ,遍歷效果可能會(huì)碰到如下問題: 新增的鍵可能沒有遍歷到, 遍歷出了重復(fù)的鍵等情況, 也就是說scan并不能保證完整的遍歷出來所有的鍵, 我們在使用的過程中需要考慮到這一點(diǎn)。

總結(jié)

以上是生活随笔為你收集整理的Redis进阶-如何从海量的 key 中找出特定的key列表 Scan详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 高级毛片 | 香蕉久久夜色精品升级完成 | 五月开心网 | 日本高清免费不卡视频 | 99久久99久久精品国产片果冰 | 午夜伦理剧场 | 亚洲高清一区二区三区 | 完美搭档在线观看 | 边吃奶边添下面好爽 | 在线观看sm | 婷婷五月小说 | 欧洲三级在线 | 精品一区二区三区人妻 | 亚洲男女啪啪 | 欧美性xxxxx极品少妇 | 色乱码一区二区三区 | 中文字幕人妻色偷偷久久 | 好男人www在线视频 我们的2018在线观看免费高清 | 深夜福利一区二区三区 | 激情黄色小说网站 | 欧美午夜在线视频 | 日韩福利在线播放 | 激情欧美综合 | 成人免费在线电影 | 日本美女黄视频 | 中文在线观看高清视频 | 三浦惠理子aⅴ一二三区 | 久久久久久福利 | 亚洲精品国产无码 | 在线观看一二区 | 国产一线二线在线观看 | 懂色av粉嫩av蜜乳av | 狠狠干天天色 | 性猛交ⅹxxx富婆视频 | 伊人青青久 | 成人黄色免费网 | 2018天天弄 | 黄色片视频网站 | 狠狠干很很操 | 中国老熟妇自拍hd发布 | 国产又黄又粗又爽 | 日韩三级视频在线观看 | 午夜8888 | 亚洲精品视频在线看 | 性欧美日本 | 日韩深夜在线 | 日xxxx| 久久高清 | 欧美日韩国产在线播放 | 免费婷婷 | 九色福利视频 | 欧美日韩黄色网 | 成人福利视频在线 | 想要视频在线 | 综合久久影院 | 爱情岛论坛永久入口 | 美女视频黄色在线观看 | 波多野结衣一区二区三区中文字幕 | 一区二区视频在线 | 日韩91| 人妻熟妇又伦精品视频a | 国产精品一区二区av白丝下载 | 国产精品羞羞答答在线观看 | 欧美日韩在线视频免费观看 | 欧美成人高清在线 | 在线日韩精品视频 | 久久精品国产电影 | 欧美自拍视频 | 国产精品久久久久久久久久久不卡 | 免费国产精品视频 | 日本精品一区二区三区在线观看 | 欧美浮力影院 | 日韩欧美一级片 | 麻豆传媒一区二区 | 欧美一区国产一区 | 99热日本| 国内自拍网站 | 福利国产视频 | 亚洲国产精品无码久久 | 日韩wwww | 久久国产精品久久久久久电车 | 色屋在线 | 欧美91精品久久久久国产性生爱 | 国产一区二区成人 | 久草欧美视频 | 99热1| 国产精品久久精品三级 | 91插插插插插插插 | 一起操在线 | 国语av在线 | 免费欧美视频 | 国产无遮挡裸体免费视频 | 好色999| 国产免费久久久 | 久久久久久久一区二区三区 | 欧美a级黄色 | 国内激情自拍 | 亚洲熟女一区二区三区 | 欧美草草 |