婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Redis中scan命令的深入講解

Redis中scan命令的深入講解

熱門標簽:高碑店市地圖標注app 地圖標注工廠入駐 臺灣電銷 南京手機外呼系統(tǒng)廠家 b2b外呼系統(tǒng) 四川穩(wěn)定外呼系統(tǒng)軟件 400電話辦理的口碑 一個地圖標注多少錢 廊坊外呼系統(tǒng)在哪買

前言

熟悉Redis的人都知道,它是單線程的。因此在使用一些時間復雜度為O(N)的命令時要非常謹慎。可能一不小心就會阻塞進程,導致Redis出現卡頓。

有時,我們需要針對符合條件的一部分命令進行操作,比如刪除以test_開頭的key。那么怎么獲取到這些key呢?在Redis2.8版本之前,我們可以使用keys命令按照正則匹配得到我們需要的key。但是這個命令有兩個缺點:

  • 沒有l(wèi)imit,我們只能一次性獲取所有符合條件的key,如果結果有上百萬條,那么等待你的就是“無窮無盡”的字符串輸出。
  • keys命令是遍歷算法,時間復雜度是O(N)。如我們剛才所說,這個命令非常容易導致Redis服務卡頓。因此,我們要盡量避免在生產環(huán)境使用該命令。

在滿足需求和存在造成Redis卡頓之間究竟要如何選擇呢?面對這個兩難的抉擇,Redis在2.8版本給我們提供了解決辦法——scan命令。

相比于keys命令,scan命令有兩個比較明顯的優(yōu)勢:

  • scan命令的時間復雜度雖然也是O(N),但它是分次進行的,不會阻塞線程。
  • scan命令提供了limit參數,可以控制每次返回結果的最大條數。

這兩個優(yōu)勢就幫助我們解決了上面的難題,不過scan命令也并不是完美的,它返回的結果有可能重復,因此需要客戶端去重。至于為什么會重復,相信你看完本文之后就會有答案了。

關于scan命令的基本用法,可以參看Redis命令詳解:Keys一文中關于SCAN命令的介紹。

SCAN 命令

SCAN命令的有SCAN,SSCAN,HSCAN,ZSCAN。

SCAN的話就是遍歷所有的keys

其他的SCAN命令的話是SCAN選中的集合。

SCAN命令是增量的循環(huán),每次調用只會返回一小部分的元素。所以不會有KEYS命令的坑。

SCAN命令返回的是一個游標,從0開始遍歷,到0結束遍歷。

今天我們主要從底層的結構和源碼的角度來討論scan是如何工作的。

Redis的結構

Redis使用了Hash表作為底層實現,原因不外乎高效且實現簡單。說到Hash表,很多Java程序員第一反應就是HashMap。沒錯,Redis底層key的存儲結構就是類似于HashMap那樣數組+鏈表的結構。其中第一維的數組大小為2n(n>=0)。每次擴容數組長度擴大一倍。

scan命令就是對這個一維數組進行遍歷。每次返回的游標值也都是這個數組的索引。limit參數表示遍歷多少個數組的元素,將這些元素下掛接的符合條件的結果都返回。因為每個元素下掛接的鏈表大小不同,所以每次返回的結果數量也就不同。

SCAN的遍歷順序

關于scan命令的遍歷順序,我們可以用一個小栗子來具體看一下。

127.0.0.1:6379> keys *
1) "db_number"
2) "key1"
3) "myKey"
127.0.0.1:6379> scan 0 MATCH * COUNT 1
1) "2"
2) 1) "db_number"
127.0.0.1:6379> scan 2 MATCH * COUNT 1
1) "1"
2) 1) "myKey"
127.0.0.1:6379> scan 1 MATCH * COUNT 1
1) "3"
2) 1) "key1"
127.0.0.1:6379> scan 3 MATCH * COUNT 1
1) "0"
2) (empty list or set)

我們的Redis中有3個key,我們每次只遍歷一個一維數組中的元素。如上所示,SCAN命令的遍歷順序是

0->2->1->3

這個順序看起來有些奇怪。我們把它轉換成二進制就好理解一些了。

00->10->01->11

我們發(fā)現每次這個序列是高位加1的。普通二進制的加法,是從右往左相加、進位。而這個序列是從左往右相加、進位的。這一點我們在redis的源碼中也得到印證。

在dict.c文件的dictScan函數中對游標進行了如下處理

v = rev(v);
v++;
v = rev(v);

意思是,將游標倒置,加一后,再倒置,也就是我們所說的“高位加1”的操作。

這里大家可能會有疑問了,為什么要使用這樣的順序進行遍歷,而不是用正常的0、1、2……這樣的順序呢,這是因為需要考慮遍歷時發(fā)生字典擴容與縮容的情況(不得不佩服開發(fā)者考慮問題的全面性)。

我們來看一下在SCAN遍歷過程中,發(fā)生擴容時,遍歷會如何進行。加入我們原始的數組有4個元素,也就是索引有兩位,這時需要把它擴充成3位,并進行rehash。

原來掛接在xx下的所有元素被分配到0xx和1xx下。在上圖中,當我們即將遍歷10時,dict進行了rehash,這時,scan命令會從010開始遍歷,而000和100(原00下掛接的元素)不會再被重復遍歷。

再來看看縮容的情況。假設dict從3位縮容到2位,當即將遍歷110時,dict發(fā)生了縮容,這時scan會遍歷10。這時010下掛接的元素會被重復遍歷,但010之前的元素都不會被重復遍歷了。所以,縮容時還是可能會有些重復元素出現的。

Redis的rehash

rehash是一個比較復雜的過程,為了不阻塞Redis的進程,它采用了一種漸進式的rehash的機制。

/* 字典 */
typedef struct dict {
 // 類型特定函數
 dictType *type;
 // 私有數據
 void *privdata;
 // 哈希表
 dictht ht[2];
 // rehash 索引
 // 當 rehash 不在進行時,值為 -1
 int rehashidx; /* rehashing not in progress if rehashidx == -1 */
 // 目前正在運行的安全迭代器的數量
 int iterators; /* number of iterators currently running */
} dict;

在Redis的字典結構中,有兩個hash表,一個新表,一個舊表。在rehash的過程中,redis將舊表中的元素逐步遷移到新表中,接下來我們看一下dict的rehash操作的源碼。

/* Performs N steps of incremental rehashing. Returns 1 if there are still
 * keys to move from the old to the new hash table, otherwise 0 is returned.
 *
 * Note that a rehashing step consists in moving a bucket (that may have more
 * than one key as we use chaining) from the old to the new hash table, however
 * since part of the hash table may be composed of empty spaces, it is not
 * guaranteed that this function will rehash even a single bucket, since it
 * will visit at max N*10 empty buckets in total, otherwise the amount of
 * work it does would be unbound and the function may block for a long time. */
int dictRehash(dict *d, int n) {
 int empty_visits = n*10; /* Max number of empty buckets to visit. */
 if (!dictIsRehashing(d)) return 0;

 while(n--  d->ht[0].used != 0) {
 dictEntry *de, *nextde;

 /* Note that rehashidx can't overflow as we are sure there are more
  * elements because ht[0].used != 0 */
 assert(d->ht[0].size > (unsigned long)d->rehashidx);
 while(d->ht[0].table[d->rehashidx] == NULL) {
  d->rehashidx++;
  if (--empty_visits == 0) return 1;
 }
 de = d->ht[0].table[d->rehashidx];
 /* Move all the keys in this bucket from the old to the new hash HT */
 while(de) {
  uint64_t h;

  nextde = de->next;
  /* Get the index in the new hash table */
  h = dictHashKey(d, de->key)  d->ht[1].sizemask;
  de->next = d->ht[1].table[h];
  d->ht[1].table[h] = de;
  d->ht[0].used--;
  d->ht[1].used++;
  de = nextde;
 }
 d->ht[0].table[d->rehashidx] = NULL;
 d->rehashidx++;
 }

 /* Check if we already rehashed the whole table... */
 if (d->ht[0].used == 0) {
 zfree(d->ht[0].table);
 d->ht[0] = d->ht[1];
 _dictReset(d->ht[1]);
 d->rehashidx = -1;
 return 0;
 }

 /* More to rehash... */
 return 1;
}

通過注釋我們就能了解到,rehash的過程是以bucket為基本單位進行遷移的。所謂的bucket其實就是我們前面所提到的一維數組的元素。每次遷移一個列表。下面來解釋一下這段代碼。

  • 首先判斷一下是否在進行rehash,如果是,則繼續(xù)進行;否則直接返回。
  • 接著就是分n步開始進行漸進式rehash。同時還判斷是否還有剩余元素,以保證安全性。
  • 在進行rehash之前,首先判斷要遷移的bucket是否越界。
  • 然后跳過空的bucket,這里有一個empty_visits變量,表示最大可訪問的空bucket的數量,這一變量主要是為了保證不過多的阻塞Redis。
  • 接下來就是元素的遷移,將當前bucket的全部元素進行rehash,并且更新兩張表中元素的數量。
  • 每次遷移完一個bucket,需要將舊表中的bucket指向NULL。
  • 最后判斷一下是否全部遷移完成,如果是,則收回空間,重置rehash索引,否則告訴調用方,仍有數據未遷移。

由于Redis使用的是漸進式rehash機制,因此,scan命令在需要同時掃描新表和舊表,將結果返回客戶端。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • php redis擴展支持scan命令實現方法
  • Redis中Scan命令的基本使用教程
  • 詳解Redis SCAN命令實現有限保證的原理
  • Redis Scan命令的基本使用方法
  • Redis中Scan命令的踩坑實錄
  • redis中scan命令的基本實現方法

標簽:拉薩 伊春 泰州 定州 河源 南寧 畢節(jié) 甘南

巨人網絡通訊聲明:本文標題《Redis中scan命令的深入講解》,本文關鍵詞  Redis,中,scan,命令,的,深入,;如發(fā)現本文內容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內容系統(tǒng)采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Redis中scan命令的深入講解》相關的同類信息!
  • 本頁收集關于Redis中scan命令的深入講解的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    日韩国产在线一| 久久久久久99久久久精品网站| 亚洲成人精品影院| 色www精品视频在线观看| 国产精品麻豆久久久| 国产欧美中文在线| 欧美日韩一区国产| 91福利国产成人精品照片| 欧美剧情片在线观看| 丝袜美腿亚洲色图| 久久久国产精品午夜一区ai换脸| 亚洲人成小说网站色在线| 欧美精品一区二区久久婷婷| 五月天精品一区二区三区| 亚洲成人精品一区二区| 日韩一区二区免费在线电影| 欧美日韩亚洲综合在线| 看电影不卡的网站| 国产精品一区二区久激情瑜伽| 4438x亚洲最大成人网| 奇米影视7777精品一区二区| 欧美精品一区二区三区高清aⅴ| 久久99国产精品免费网站| www.日韩在线| 亚洲影院在线观看| 亚洲午夜久久久| bt欧美亚洲午夜电影天堂| 色婷婷久久综合| 91精品国产一区二区| 国产精品夫妻自拍| 国产一区二区三区美女| 色香蕉久久蜜桃| 菠萝蜜视频在线观看一区| 日韩免费观看高清完整版在线观看| 久久天堂av综合合色蜜桃网| 欧美va日韩va| 亚洲三级免费电影| 国内久久精品视频| 91视频观看视频| 国产精品女同互慰在线看| 91蝌蚪国产九色| 亚洲人妖av一区二区| 国产mv日韩mv欧美| 亚洲黄色尤物视频| 亚洲成人av电影在线| 亚洲在线成人精品| 国产成人精品免费网站| 日韩免费一区二区| 国产亚洲综合av| 精品88久久久久88久久久| 玖玖九九国产精品| 亚洲午夜精品网| 久久精品视频在线看| 欧美久久婷婷综合色| heyzo一本久久综合| 91精品欧美一区二区三区综合在 | 一区二区三区国产精华| 欧美日本一道本| 26uuu另类欧美亚洲曰本| 国产ts人妖一区二区| 2023国产精品| 亚洲免费三区一区二区| 99国产精品国产精品毛片| 欧美韩日一区二区三区| 风流少妇一区二区| 亚洲一区在线观看免费观看电影高清 | 亚洲一二三区在线观看| 日韩成人一区二区三区在线观看| 亚洲免费av观看| 欧美一区二区三区电影| 狠狠色狠狠色合久久伊人| 国产精品乱码人人做人人爱| 欧美视频中文字幕| 午夜视频在线观看一区二区三区| 欧美一区二区三区视频| 高清日韩电视剧大全免费| 国产一区二区三区观看| 韩国成人福利片在线播放| 麻豆精品国产91久久久久久| 精品1区2区3区| 中文字幕一区二区视频| 26uuu精品一区二区在线观看| 日韩美女天天操| 欧美精品久久一区二区三区| 欧美亚洲图片小说| 欧美日韩五月天| 日韩免费电影网站| 2020日本不卡一区二区视频| 蜜桃精品视频在线观看| 国产亚洲人成网站| 亚洲一区在线电影| av成人免费在线观看| 久久综合九色欧美综合狠狠| 亚洲国产日韩a在线播放性色| 欧美午夜电影网| 97久久精品人人澡人人爽| 国产精品88av| 在线一区二区三区四区| 欧美另类久久久品| 一区二区中文视频| 九九国产精品视频| 色综合久久天天| 精品久久久久久久人人人人传媒| 久久精品国产**网站演员| 亚洲国产aⅴ天堂久久| 国产高清一区日本| 久久这里只有精品6| 日本人妖一区二区| 欧美日韩精品二区第二页| 国产精品美日韩| 国产aⅴ精品一区二区三区色成熟| 欧美区视频在线观看| 岛国精品在线观看| 中文字幕一区二区三区不卡| 欧美在线视频全部完| 美女mm1313爽爽久久久蜜臀| 亚洲高清免费观看| 日韩欧美国产一区二区在线播放 | 91在线码无精品| 一区二区三区在线视频观看| 欧美一区二区女人| 91丨九色丨国产丨porny| 久久精品国产成人一区二区三区| 99精品视频一区二区| 青青草视频一区| 亚洲日本在线视频观看| 国产午夜一区二区三区| 欧美精品色一区二区三区| 成人av综合一区| 精品精品欲导航| av高清久久久| 日韩av电影一区| 欧美激情一区二区在线| 欧美日韩黄色一区二区| 狠狠狠色丁香婷婷综合激情| 成人美女在线观看| 亚洲午夜电影网| 精品少妇一区二区三区免费观看| 亚洲午夜电影在线| 国产清纯在线一区二区www| 五月天激情小说综合| 26uuu色噜噜精品一区| 成人午夜精品在线| 成人小视频免费观看| 欧美一区二区三区成人| 欧美日韩亚洲综合一区| 国产成人av网站| 国产乱妇无码大片在线观看| 日本网站在线观看一区二区三区| 免费不卡在线观看| 91精品国产综合久久精品图片| 91麻豆精品久久久久蜜臀| 成人黄动漫网站免费app| 777精品伊人久久久久大香线蕉| 在线视频中文字幕一区二区| 精品国产乱码久久久久久老虎 | 99国产精品久久久久| 久久伊99综合婷婷久久伊| 日韩在线一二三区| 91社区在线播放| 亚洲色图欧美在线| 日韩高清国产一区在线| 精品欧美久久久| 色乱码一区二区三区88| 亚洲高清在线视频| 精品国产不卡一区二区三区| 石原莉奈在线亚洲三区| 亚洲精品一区二区三区精华液| 成人午夜激情视频| 日韩欧美国产三级| 欧美一级在线免费| 欧美日韩一区二区三区在线| 亚洲欧洲成人自拍| 国产视频在线观看一区二区三区| 极品销魂美女一区二区三区| 午夜精品在线视频一区| 亚洲1区2区3区4区| 国产一区二区三区久久久| 在线观看三级视频欧美| 国产成人综合网| av在线不卡电影| 在线国产亚洲欧美| 97久久人人超碰| 午夜亚洲国产au精品一区二区| 精品在线播放午夜| 手机精品视频在线观看| 亚洲欧洲国产日韩| 成人免费毛片片v| 麻豆传媒一区二区三区| 亚洲一区二区三区四区的| 日韩视频一区二区三区 | 成人av资源在线| 精品在线播放午夜| 国产夫妻精品视频| 在线中文字幕一区二区| 91精品国产综合久久精品| 首页亚洲欧美制服丝腿| 久久久久国产一区二区三区四区| 黑人巨大精品欧美一区| a4yy欧美一区二区三区|