最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

redis中scan命令的基本實(shí)現(xiàn)方法

 更新時間:2020年10月04日 10:38:32   作者:一張狗  
這篇文章主要給大家介紹了關(guān)于redis中scan命令的基本實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

在一個天朗氣清的日子,小灰登上了線上的redis打算查詢數(shù)據(jù)。然而他只記得前綴而不知道整個鍵是多少,于是在命令行敲入了“keys xxx*”命令。

瞬間服務(wù)卡死,報警郵件堆滿了郵箱,而小灰,只能目瞪狗呆的等待著即將降臨的case study。

基本上,keys *命令都是在線上是被運(yùn)維禁止的。

redis的鍵在鍵值對大小大于hash-max-ziplist-value且個數(shù)小于hash-max-ziplist-entries的時候,是存放在散列表數(shù)據(jù)結(jié)構(gòu)中的,在運(yùn)行keys命令的時候,需要遍歷數(shù)據(jù)庫鍵空間,把所有鍵都取出來后與keys后面的pattern匹配。

在鍵很多的情況下,redis可能的卡頓會在秒級以上,導(dǎo)致所有流量都打到數(shù)據(jù)庫,使得數(shù)據(jù)庫雪崩。

那我們怎么才能夠在查找到目標(biāo)鍵呢?在redis2.8.0的時候加入了scan命令,可以分批次掃描redis鍵。雖然在應(yīng)用的時候會使得要查詢到全部符合要求的key的時間變長,但是大大大大減少了redis卡頓的幾率

在這里先補(bǔ)充一下背景:

redis中的字典rehash是漸進(jìn)式哈希,即不是一次性把所有的鍵都遷移到新的哈希表,而是在下面兩種情況下遷移數(shù)據(jù):
每次哈希表操作的時候,如果當(dāng)前正在rehash,則遷移一個節(jié)點(diǎn);
服務(wù)空閑時,會rehash一百個節(jié)點(diǎn)。

scan命令可以保證在(沒有鍵修改的)字典正在rehash的過程中做到以下兩點(diǎn):

  • 不出現(xiàn)重復(fù)數(shù)據(jù)
  • 不遺漏數(shù)據(jù)

那scan命令是怎么做到在rehash過程中都能不重復(fù)不遺漏地遍歷所有節(jié)點(diǎn)的呢?讓我們來一起走讀一下源碼。

Let's GO!

在使用scan命令的時候,我們每次傳入一個游標(biāo)(從0開始),然后下一輪繼續(xù)使用本輪redis返回的游標(biāo)。scan字典的核心函數(shù)是dictScan,而dictScan的更新游標(biāo)的核心代碼如下:

v |= ~m0;//或者m1
/* Increment the reverse cursor */
v = rev(v);
v++;
v = rev(v);

其中m0、m1為當(dāng)前哈希表大小減一,rev是二進(jìn)制逆序。

看到這里,不知道在座的各位是不是也是跟我一樣是下面這個表情

讓我們來模擬一下問題,就清楚了。

我們假設(shè)現(xiàn)在在一個四個節(jié)點(diǎn)的哈希表中遍歷,如下圖,游標(biāo)的遍歷節(jié)點(diǎn)為:0 -> 2 -> 1 -> 3 :

再來模擬8節(jié)點(diǎn)的情況:

看到這里是不是稍微明白了,上面那段代碼就是在當(dāng)前的有效位數(shù)(比如四節(jié)點(diǎn)則有效位數(shù)2)范圍內(nèi),從左到右進(jìn)一位。

假設(shè)在遍歷了0,返回2之后,字典進(jìn)行了擴(kuò)容,則接下來應(yīng)該訪問 2 -> 6 -> 1 -> 5 -> 3 -> 7。

小灰:咦,那4不是遺漏了嗎?

4已經(jīng)在第一輪遍歷0的時候,把擴(kuò)容后的4的數(shù)據(jù)也訪問了。

所以,假設(shè)擴(kuò)容前有效位為m,因?yàn)閞edis的哈希表擴(kuò)容每次都是當(dāng)前節(jié)點(diǎn)滿了( use==size)的時候擴(kuò)容為大于size的2^N,所以擴(kuò)容后有效位則為m+1。

上面那段代碼其實(shí)是保持低位的m位不變,高位一個為0一個為1。這樣就保證了擴(kuò)容后,跳過了的節(jié)點(diǎn)已經(jīng)在之前被訪問過,因?yàn)樘^的節(jié)點(diǎn)是被訪問過的節(jié)點(diǎn)分出來的。

縮容同理,可以自己推一下。

看到這里,是不是覺得redis的scan游標(biāo)設(shè)計的很巧妙呢?

小灰:原來如此,看來我又可以去查數(shù)據(jù)了呢!

最后附上完整的rehash過程中scan的代碼:

// 指向兩個哈希表
t0 = &d->ht[0];
t1 = &d->ht[1];

/* Make sure t0 is the smaller and t1 is the bigger table */
// 確保 t0 比 t1 要小
if (t0->size > t1->size) {
 t0 = &d->ht[1];
 t1 = &d->ht[0];
}

// 記錄掩碼
m0 = t0->sizemask;
m1 = t1->sizemask;

/* Emit entries at cursor */
// 指向桶,并迭代桶中的所有節(jié)點(diǎn)
de = t0->table[v & m0];
while (de) {//迭代第一張小hash表
 next = de->next;
 fn(privdata, de);
 de = next;
}

/* Iterate over indices in larger table that are the expansion
 * of the index pointed to by the cursor in the smaller table */
do {//迭代第二張大hash表
 /* Emit entries at cursor */
 if (bucketfn) bucketfn(privdata, &t1->table[v & m1]);
 de = t1->table[v & m1];
 while (de) {
  next = de->next;
  fn(privdata, de);
  de = next;
 }

 //計算一個哈希表節(jié)點(diǎn)索引的方法 是 hash(key)&mask。哈希表容量為 8,則 mask 為 111,因此,節(jié)點(diǎn)的索引值就取決于哈希值的低 3 bit,
 // 設(shè)索引值是 abc。如果哈希表容量為 16,則 mask 為 1111,該節(jié)點(diǎn)的哈希值不變,而索引值是 ?abc,其中 ? 取 0 或 1 中的一個,
 // 也就是說,該節(jié)點(diǎn)在容量為 16 的哈希表中,索引要么是 0abc 要么是 1abc。以此類推,如果哈希表容量為32,
 // 則該節(jié)點(diǎn)的索引可能是 00abc,01abc,10abc 或者 11abc 中的一個。/* Increment the reverse cursor not covered by the smaller mask.*/
 v |= ~m1;//用于保留 v 的低 n 位數(shù),其余位全置為 1
 //下面這一段,最終得到的新 v,就是向最高位加 1,且向低位方向進(jìn)位
 v = rev(v);//將 v 的二進(jìn)制位進(jìn)行翻轉(zhuǎn),所以,v的低 n 位數(shù)成了高 n 位數(shù),并且進(jìn)行了翻轉(zhuǎn)
 v++;
 v = rev(v);//再次二進(jìn)制翻轉(zhuǎn)

 /* Continue while bits covered by mask difference is non-zero */
} while (v & (m0 ^ m1));//終止條件是 v的高位區(qū)別位沒有1了,其實(shí)就是說到頭了。

總結(jié)

到此這篇關(guān)于redis中scan命令的基本實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)redis中scan命令實(shí)現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis所實(shí)現(xiàn)的Reactor模型設(shè)計方案

    Redis所實(shí)現(xiàn)的Reactor模型設(shè)計方案

    這篇文章主要介紹了Redis所實(shí)現(xiàn)的Reactor模型,本文將帶領(lǐng)讀者從源碼的角度來查看redis關(guān)于reactor模型的設(shè)計,需要的朋友可以參考下
    2024-06-06
  • 關(guān)于Redis庫存超賣問題的分析

    關(guān)于Redis庫存超賣問題的分析

    在高并發(fā)場景下進(jìn)行優(yōu)惠券秒殺測試時,發(fā)現(xiàn)由于并發(fā)操作導(dǎo)致了超賣問題,即理論上只能賣出100個優(yōu)惠券,實(shí)際賣出了102個,分析原因,是因?yàn)樵诟卟l(fā)環(huán)境下,多個線程同時操作庫存,導(dǎo)致數(shù)據(jù)不一致,提出了兩種解決方案:悲觀鎖和樂觀鎖
    2024-11-11
  • Redis分布式鎖防止緩存擊穿的實(shí)現(xiàn)

    Redis分布式鎖防止緩存擊穿的實(shí)現(xiàn)

    本文主要介紹了Redis分布式鎖防止緩存擊穿的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Redis中pipeline(管道)的實(shí)現(xiàn)示例

    Redis中pipeline(管道)的實(shí)現(xiàn)示例

    Redis管道(Pipeline)技術(shù)是一種提高數(shù)據(jù)處理效率的機(jī)制,允許客戶端通過一次網(wǎng)絡(luò)往返(RTT)發(fā)送多個命令到服務(wù)端,并一次性接收所有響應(yīng),本文就來實(shí)現(xiàn)管道,感興趣的可以了解一下
    2024-10-10
  • redis中hash數(shù)據(jù)結(jié)構(gòu)及說明

    redis中hash數(shù)據(jù)結(jié)構(gòu)及說明

    這篇文章主要介紹了redis中hash數(shù)據(jù)結(jié)構(gòu)及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • redis之?dāng)?shù)據(jù)過期清除策略、緩存淘汰策略詳解

    redis之?dāng)?shù)據(jù)過期清除策略、緩存淘汰策略詳解

    這篇文章主要介紹了redis之?dāng)?shù)據(jù)過期清除策略、緩存淘汰策略的用法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • redis cluster集群模式下實(shí)現(xiàn)批量可重入鎖

    redis cluster集群模式下實(shí)現(xiàn)批量可重入鎖

    本文主要介紹了使用redis cluster集群版所遇到的問題解決方案及redis可重入鎖是否會有死鎖的問題等,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • redis生成全局id的實(shí)現(xiàn)步驟

    redis生成全局id的實(shí)現(xiàn)步驟

    生成全局唯一的標(biāo)識符是非常常見的需求,本文主要介紹了redis生成全局id的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05
  • 玩轉(zhuǎn)Redis搭建集群之Sentinel詳解

    玩轉(zhuǎn)Redis搭建集群之Sentinel詳解

    這篇文章主要給大家介紹了關(guān)于Redis搭建集群之Sentinel的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • 解決Redis報錯MISCONF?Redis?is?configured?to?save?RDB?snapshots

    解決Redis報錯MISCONF?Redis?is?configured?to?save?RDB?snap

    這篇文章主要給大家介紹了關(guān)于如何解決Redis報錯MISCONF?Redis?is?configured?to?save?RDB?snapshots的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11

最新評論

绥滨县| 五台县| 霸州市| 怀柔区| 上高县| 辽阳市| 吉木萨尔县| 东乌珠穆沁旗| 金山区| 固原市| 吉木萨尔县| 仙游县| 图们市| 平顺县| 大城县| 吉木乃县| 章丘市| 都昌县| 苏州市| 盈江县| 关岭| 平湖市| 同德县| 苏尼特右旗| 油尖旺区| 班玛县| 佳木斯市| 响水县| 揭阳市| 通河县| 福鼎市| 桑日县| 巴南区| 镇赉县| 京山县| 海淀区| 巴楚县| 陇南市| 芮城县| 黎川县| 清徐县|