簡(jiǎn)介
在巨大的數(shù)據(jù)量的情況下蜻拨,做查找符合某種規(guī)則的Key的信息,這里就有兩種方式:
keys命令:
簡(jiǎn)單粗暴桩引,但是由于Redis是單線程缎讼,keys命令是以阻塞的方式執(zhí)行的,keys是以遍歷的方式實(shí)現(xiàn)的復(fù)雜度是 O(n)坑匠,Redis庫(kù)中的key越多血崭,查找實(shí)現(xiàn)代價(jià)越大,產(chǎn)生的阻塞時(shí)間越長(zhǎng)厘灼。
can命令:
以非阻塞的方式實(shí)現(xiàn)key值的查找夹纫,絕大多數(shù)情況下是可以替代keys命令的,可選性更強(qiáng)设凹。
scan相關(guān)命令
都是用于增量迭代集合元素舰讹。
SCAN 命令用于迭代當(dāng)前數(shù)據(jù)庫(kù)中的數(shù)據(jù)庫(kù)鍵。
SSCAN 命令用于迭代集合鍵中的元素闪朱。
HSCAN 命令用于迭代哈希鍵中的鍵值對(duì)跺涤。
ZSCAN 命令用于迭代有序集合中的元素(包括元素成員和元素分值)。
之后的例子會(huì)以sscan為例监透。
命令參數(shù)
redis 127.0.0.1:6379> SSCAN key cursor [MATCH pattern] [COUNT count]
Key:查詢的相關(guān)集合名稱
cursor: 游標(biāo)值桶错,第一次迭代使用 0 作為游標(biāo),表示開(kāi)始一次新的迭代
[MATCH pattern] :模糊匹配
[COUNT count] :每次的查詢條數(shù)胀蛮,默認(rèn)值為 10
1院刁、創(chuàng)建數(shù)組
在上面這個(gè)例子中, 第一次迭代使用 0 作為游標(biāo)粪狼,表示開(kāi)始一次新的迭代退腥。
第二次迭代使用的是第一次迭代時(shí)返回的游標(biāo)任岸, 也即是命令回復(fù)第一個(gè)元素的值 —— 3 。
以 0 作為游標(biāo)開(kāi)始一次新的迭代狡刘, 一直調(diào)用 SCAN 命令享潜, 直到命令返回游標(biāo) 0 , 我們稱這個(gè)過(guò)程為一次完整遍歷(full iteration)嗅蔬。
在同一時(shí)間剑按, 可以有任意多個(gè)客戶端對(duì)同一數(shù)據(jù)集進(jìn)行迭代, 客戶端每次執(zhí)行迭代都需要傳入一個(gè)游標(biāo)澜术, 并在迭代執(zhí)行之后獲得一個(gè)新的游標(biāo)艺蝴, 而這個(gè)游標(biāo)就包含了迭代的所有狀態(tài), 因此鸟废, 服務(wù)器無(wú)須為迭代記錄任何狀態(tài)猜敢,同樣也不會(huì)阻塞線程。
2盒延、解讀match
match:通過(guò)提供一個(gè) glob 風(fēng)格的模式參數(shù)缩擂,讓命令只返回和給定模式相匹配的元素。
前方高能預(yù)警:match的底層操作是在從數(shù)據(jù)集中取出元素之后添寺,向客戶端返回元素之前的這段時(shí)間內(nèi)進(jìn)行的胯盯, 如果返回的結(jié)果集中沒(méi)有匹配,那么可能會(huì)在多次執(zhí)行中都不返回任何元素畦贸。
所以單次返回的結(jié)果是空的并不意味著遍歷結(jié)束,而要看返回的游標(biāo)值是否為零楞捂。
3薄坏、解讀count
count:可以控制每次返回結(jié)果的最大條數(shù),count只是一個(gè) hint寨闹,返回的結(jié)果可多可少胶坠。
注意
返回的結(jié)果可能會(huì)有重復(fù),需要客戶端去重復(fù)繁堡,這點(diǎn)非常重要沈善;
遍歷的過(guò)程中如果有數(shù)據(jù)修改,改動(dòng)后的數(shù)據(jù)能不能遍歷到是不確定的椭蹄。
實(shí)操
在線上有時(shí)候需要對(duì)大量key進(jìn)行刪除操作闻牡,有幾個(gè)風(fēng)險(xiǎn)點(diǎn):
一次性查詢所指定的key, 數(shù)量較大可能造成redis服務(wù)卡頓,Redis是單線程程序绳矩,順序執(zhí)行所有指令罩润,其它指令必須等到當(dāng)前的 keys 指令執(zhí)行完了才可以繼續(xù)。
如何從海量的 key 中找出滿足特定前綴的 key?
但是通過(guò)用scan翼馆,我們就可以指定有共性的key割以,并指定一次性查詢條件金度。
for (String cacheName : cacheNames) {
String keyPrefix = new String(cachePrefix.prefix(cacheName)); //拼接我們的
ScanParams scanParams = new ScanParams().match(keyPrefix.concat("*")).count(200); //指定規(guī)則
String cur = ScanParams.SCAN_POINTER_START; //游標(biāo)初始值為0
boolean hasNext = true;
int count = 0;
while (hasNext) {
count++;
ScanResult<String> scanResult = jedisCluster.scan(cur, scanParams); //key的正則表達(dá)式
List<String> keys = scanResult.getResult();
for (String key : keys) {
jedisCluster.del(key);
}
cur = scanResult.getStringCursor(); //返回用于下次遍歷的游標(biāo)
if (StringUtils.equals("0", cur)) { //說(shuō)明遍歷已結(jié)束
hasNext = false;
}
}
log.info("redis cache evict {} {}", cacheName, count);
}
}
原文鏈接:
sugarYang
https://juejin.im/post/5ea2a29de51d4546fd48303c文源網(wǎng)絡(luò),僅供學(xué)習(xí)之用严沥,如有侵權(quán)請(qǐng)聯(lián)系刪除猜极。
我將面試題和答案都整理成了PDF文檔,還有一套學(xué)習(xí)資料消玄,涵蓋Java虛擬機(jī)跟伏、spring框架、Java線程莱找、數(shù)據(jù)結(jié)構(gòu)酬姆、設(shè)計(jì)模式等等,但不僅限于此奥溺。
關(guān)注公眾號(hào)【java圈子】獲取資料辞色,還有優(yōu)質(zhì)文章每日送達(dá)。