精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

因為不會Redis的scan命令,我被開除了

存儲 存儲軟件 Redis
那個深夜,我登上了公司的服務器,在 Redis 命令行里敲入 keys* 后,線上開始報警,服務瞬間被卡死。

 那個深夜,我登上了公司的服務器,在 Redis 命令行里敲入 keys* 后,線上開始報警,服務瞬間被卡死。

[[285581]]
圖片來自 Pexels 

我只能舉起雙手,焦急地等待幾千萬 key 被慢慢掃描,束手無策萬念俱灰的時候,我收到了 Leader 的短信:你明天不用來上班了。

[[285582]] 

雖然上面是我的臆想,事實上很多公司的運維也會禁用這些命令,來防止開發出錯。

但我在群里依然看到有同學在問“為什么 Redis 不能用 keys?我覺得挺好的呀”時,為了不讓上面的情況發生,我決定寫下這篇文章。

如何才能優雅地遍歷 Redis?作為一種可以稱為數據庫的組件,這是多么理所應當的要求。

終于,Redis 在 2.8.0 版本新增了眾望所歸的 scan 操作,從此再也不用擔心敲入了 keys*,然后等著定時炸彈的引爆。

學會使用 scan 并不困難,那么問題又來了,它是如何遍歷的?當遍歷過程中加入了新的 key,當遍歷過程中發生了擴容,Redis 是如何解決的?

抱著深入學習的態度,以及為了能夠將來在面試官面前談笑風生,讓我們一起來借此探索 Redis 的設計原理。

[[285583]] 

開門見山,首先讓我們來總結一下 scan 的優缺點。

優點如下:

  • 提供鍵空間的遍歷操作,支持游標,復雜度 O(1),整體遍歷一遍只需要 O(N)。
  • 提供結果模式匹配。
  • 支持一次返回的數據條數設置,但僅僅是個 hints,有時候返回更多。
  • 弱狀態,所有狀態只需要客戶端維護一個游標。

缺點如下:

  • 無法提供完整的快照遍歷,也就是中間如果有數據修改,可能有些涉及改動的數據遍歷不到。
  • 每次返回的數據條數不一定,極度依賴內部實現。
  • 返回的數據可能有重復,應用層需要能夠處理重入邏輯。

所以 scan 是一個能夠滿足需求,但也不是完美無瑕的命令。下面來介紹一下原理,scan 到底是如何實現的?

scan,hscan 等命令主要都是借用了通用的 scan 操作函數:scanGenericCommand 。

scanGenericCommand 函數分為以下幾步:

  • 解析 count 和 match 參數,如果沒有指定 count,默認返回 10 條數據。
  • 開始迭代集合,如果是 key 保存為 ziplist 或者 intset,則一次性返回所有數據,沒有游標(游標值直接返回 0)。

由于 Redis 設計,只有數據量比較小的時候才會保存為 ziplist 或者 intset,所以此處不會影響性能。

游標在保存為 hash 的時候發揮作用,具體入口函數為 dictScan,下文詳細描述。

  • 根據 match 參數過濾返回值,并且如果這個鍵已經過期也會直接過濾掉(Redis 中鍵過期之后并不會立即刪除)。

當迭代一個哈希表時,存在三種情況:

  • 從迭代開始到結束,哈希表沒有進行 rehash。
  • 從迭代開始到結束,哈希表進行了 rehash,但是每次迭代時,哈希表要么沒開始 rehash,要么已經結束了 rehash。
  • 從迭代開始到結束,某次或某幾次迭代時哈希表正在進行 rehash。

在這三種情況之下,sacn 是如何實現的?首先需要知道的前提是:Redis 中進行 rehash 擴容時會存在兩個哈希表,ht[0] 與 ht[1],rehash 是漸進式的,即不會一次性完成。

新的鍵值對會存放到 ht[1] 中并且會逐步將 ht[0] 的數據轉移到 ht[1]。全部 rehash 完畢后,ht[1] 賦值給 ht[0] 然后清空ht[1]。

[[285584]] 

模擬問題

①迭代過程中,沒有進行 rehash

這個過程比較簡單,一般來說只需要最簡單粗暴的順序迭代就可以了,這種情況下沒什么好說的。

②迭代過程中,進行過 rehash

但是字典的大小是能夠進行自動擴容的,我們不得不考慮以下兩個問題:

第一,假如字典擴容了,變成 2 倍的長度,這種情況下,能夠保證一定能遍歷所有最初的 key,但是卻會出現大量重復。

舉個例子:比如當前的 key 數組大小是 4,后來變為 8 了。假如從下表 0,1,2,3 順序掃描時,如果數組已經發生擴容。

那么前面的 0,1,2,3 slot 里面的數據會發生一部分遷移到對應的 4,5,6,7 slot 里面去,當掃描到 4,5,6,7 的 slot 時,無疑會出現值重復的情況。

需要知道的是,Redis 按如下方法計算一個當前 key 擴容后的 slot:hash(key)&(size-1)。

如圖,當字典大小從 4 擴容到 8 時,原先在 0 slot 的數據會分散到 0(000) 與 4(100) 兩個 slot,對應關系表如下:

 

第二, 如果字典縮小了,比如從 16 縮小到 8, 原先 scan 已經遍歷了 0,1,2,3 ,如果數組已經縮小。

這樣后來迭代停止在 7 號 slot,但是 8,9,10,11 這幾個 slot 的數據會分別合并到 0,1,2,3 里面去,從而 scan 就沒有掃描出這部分元素出來,無法保證可用性。

③迭代過程中,正在進行 rehash

上面考慮的情況是,在迭代過程的間隙中,rehash 已經完成。那么會不會出現迭代進行中,切換游標時,rehash 也正在進行?當然可能會發生。

如果返回游標 1 時正在進行 rehash,那么 ht[0](擴容之前的表)中的 slot1 中的部分數據可能已經 rehash 到 ht[1](擴容之后的表)中的 slot1 或者 slot4。

此時必須將 ht[0] 和 ht[1] 中的相應 slot 全部遍歷,否則可能會有遺漏數據,但是這么做好像也非常麻煩。

解決方法

為了解決以上兩個問題,Redis 使用了一種稱為:reverse binary iteration 的算法。

源碼如下:

  1. unsigned long dictScan(dict *d, unsigned long v, dictScanFunction *fn, void *privdata){ 
  2. if (!dictIsRehashing(d)) { 
  3.         t0 = (d->ht[0]); 
  4.         m0 = t0->sizemask; 
  5. /* Emit entries at cursor */ 
  6. while (de) { 
  7.             fn(privdata, de); 
  8.             de = de->next
  9. else { 
  10.         m0 = t0->sizemask; 
  11.         m1 = t1->sizemask; 
  12.         de = t0->table[v & m0]; 
  13. while (de) { 
  14.             fn(privdata, de); 
  15.             de = de->next
  16. do { 
  17.             de = t1->table[v & m1]; 
  18. while (de) { 
  19.                 fn(privdata, de); 
  20.                 de = de->next
  21.             v = (((v | m0) + 1)  & ~m0) | (v & m0); 
  22. } while (v & (m0 ^ m1)); 
  23.     v |= ~m0; 
  24.     v = rev(v); 
  25.     v++; 
  26.     v = rev(v); 
  27. return v; 

一起來理解下核心源碼,第一個 if,else 主要通過 dictIsRehashing 這個函數來判斷是否正在 rehash。

sizemask 指的是字典空間長度,假如長度為 16,那么 sizemask 的二進制為 00001111。m0 代表當前字典的長度,v 代表游標所在的索引值。

接下來關注這個片段:

  1. v |= ~m0; 
  2. v = rev(v); 
  3. v++; 
  4. v = rev(v); 

這段代碼初看好像有點摸不著頭腦,怎么多次在多次 rev?我們來看下在字典長度從 4 rehash 到 8 時,scan 是如何迭代的。

當字典長度為 4 時,m0 等于 4,二進制表示為 00000011,那么 ~m0 為 11111100,v 初始值為 0,那么 v |=~m0為11111100。

接下來看圖:

 

可以看到,第一次 dictScan 后,游標從 0 變成了 2,四次遍歷分別為 0→2→1→3,四個值都遍歷到了。

在字典長度為 8 時,遍歷情況如下:

遍歷順序為:0→4→2→6→1→5→3→7。 

是不是察覺了什么?遍歷順序是不是順序是一致的?如果還沒發現,不妨再來看看字典長度為 16 時的遍歷情況,以及三次順序的對比:

 

讓我們設想這么一個情況,字典的大小本身為 4,開始迭代,當游標剛迭代完 slot0 時,返回的下一個游標是 slot2。

此時發現字典的大小已經從 4 rehash 到 8,那么不妨繼續從 size 為 8 的 hashtable 中 slot2 處繼續迭代。

有人會說,不是把 slot4 遺漏掉了嗎?注意之前所說的擴容方式:hash(key)&(size-1),slot0 和 slot4 的內容是相同的,巧妙地避開了重復,當然,更不會遺漏。

如果你看到這里,你可能會發出和我一樣的感慨:我 X,這算法太牛 X 了。

沒錯,上面的算法是由 Pieter Noordhuis 設計實現的,Redis 之父 Salvatore Sanfilippo 對該算法的評價是“Hard to explain but awesome。”

[[285587]] 

字典擴大的情況沒問題,那么縮小的情況呢?可以仿照著自己思考一下具體步驟。答案是可能會出現重復迭代,但是不會出現遺漏,也能夠保證可用性。

迭代過程中,進行過 rehash 這種情況下的迭代已經比較完美地解決了,那么迭代過程中,正在進行 rehash 的情況是如何解決的呢?

我們繼續看源碼,之前提到過 dictIsRehashing 這個函數用來判斷是否正在進行 rehash。

那么主要就是關注這段源碼:

  1. m0 = t0->sizemask; 
  2. m1 = t1->sizemask; 
  3. de = t0->table[v & m0]; 
  4. while (de) { 
  5.             fn(privdata, de); 
  6.             de = de->next
  7. do { 
  8.             de = t1->table[v & m1]; 
  9. while (de) { 
  10.                 fn(privdata, de); 
  11.                 de = de->next
  12.             v = (((v | m0) + 1)  & ~m0) | (v & m0); 
  13. } while (v & (m0 ^ m1)); 

m0 代表 rehash 前的字典長度,假設為 4,即 00000011,m1 代表 rehash 后的字典長度,假設為 8,即 00000111。

首先當前游標 &m0 可以得到較小字典中需要迭代的 slot 的索引,然后開始循環迭代。

然后開始較大字典的迭代,首先我們關注一下循環條件:

  1. v & (m0 ^ m1) 

m0,m1 二者經過異或操作后的值為 00000100,可以看到只留下了最高位的值。

游標 v 與之做 & 操作,將其作為判斷條件,即判斷游標 v 在最高位是否還有值。

當高位為 0 時,說明較大字典已經迭代完畢。(因為較大字典的大小是較小字典的兩倍,較大字典大小的最高位一定是 1)

到此為止,我們已經將 scan 的核心源碼通讀一遍了,相信很多其間的迷惑也隨之解開。

[[285588]] 

不僅在寫代碼的時候更自信了,假如日后被面試官問起相關問題,那絕對可以趁機表現一番,想想還有點小激動。 

 

責任編輯:武曉燕 來源: 寒食君
相關推薦

2021-11-29 07:06:40

代碼公司 程序員

2020-08-27 08:54:02

腳本架構師Linux

2020-04-30 10:07:54

數據庫數據遷移Insert into

2025-07-22 09:47:26

2023-05-14 22:25:33

內存CPU

2023-03-27 07:39:07

內存溢出優化

2014-08-04 10:48:35

職場IT職場

2025-09-15 07:51:35

2021-10-19 07:06:27

服務器Kubernetes集群

2021-10-22 05:56:31

數據庫鎖表鎖定機制

2020-07-01 09:07:52

SQL索引語句

2020-03-12 07:55:50

訪問量飆升DDoS

2021-08-26 05:52:44

AI算法人工智能

2019-10-08 15:48:57

程序員技能開發者

2024-01-08 07:59:48

OpenAI人工智能AI

2020-12-18 08:28:13

Redis數據數據庫

2020-05-28 09:06:23

大數據平臺優化

2022-12-26 18:53:00

MQ宕機倉儲服務

2020-07-13 08:40:48

同事代碼

2021-02-04 07:55:28

代碼離職互聯網
點贊
收藏

51CTO技術棧公眾號

亚洲高清av一区二区三区| 99精品国产99久久久久久白柏| 国产精品理伦片| 欧美激情按摩在线| 欧美日韩精品免费观看视一区二区| 国产免费久久久久| 久久久久久久| 成人免费毛片片v| 久久精品亚洲一区| 看欧美ab黄色大片视频免费| 人妻va精品va欧美va| 欧美激情成人| 欧美亚洲一区二区在线观看| 久热这里只精品99re8久| 久久精品久久国产| 91成人噜噜噜在线播放| 亚洲天堂精品在线观看| 国产精品久久久久久久美男| 日韩网站在线播放| 麻豆mv在线看| 97精品久久久午夜一区二区三区 | 亚洲精美色品网站| 一二三在线视频| 国产成人精品白浆久久69| 无需播放器亚洲| 欧美一区二区免费观在线| 国产女人18毛片| 成年午夜在线| 禁果av一区二区三区| 日本大香伊一区二区三区| 欧美二区三区| 欧洲av在线播放| 国产在线视频一区二区| 九九热最新视频//这里只有精品| 日日干日日操日日射| 激情在线小视频| 国产精品911| 九九久久久久久久久激情| 欧美 日韩 成人| 99国内精品久久久久| 亚洲免费资源在线播放| 动漫一区二区在线| 日韩欧美中文字幕一区二区| 亚洲精品aaaaa| 日本道在线观看一区二区| 99在线精品免费视频| 日本私人网站在线观看| 美女视频网站黄色亚洲| 欧美成年人视频| 亚洲天堂美女视频| 亚洲mmav| 一区二区三区在线视频免费观看| 国产91免费视频| www日本在线| 亚洲一区不卡| 久久精品人人做人人爽| 国产精品久久免费观看| 欧美高清一级片| 黑人精品xxx一区一二区| 日本一区网站| 亚洲av无码乱码在线观看性色| 国产精品主播| 91高潮在线观看| 亚洲怡红院在线观看| 九色丨蝌蚪丨成人| 欧美视频一区二区三区| 99视频在线视频| 国产精成人品2018| 亚洲无人区一区| 日韩在线三区| 天堂地址在线www| 北条麻妃国产九九精品视频| 国产精品成熟老女人| 久久久久久久国产视频| heyzo久久| 亚洲二区在线播放视频| www.这里只有精品| 丝袜诱惑一区二区| 亚洲免费av在线| 欧美中日韩在线| 日韩黄色影院| 一区二区三区成人| 在线天堂一区av电影| 欧美在线观看在线观看| 国产调教视频一区| 久久精品日产第一区二区三区| 国产精品一级二级| 日韩影院精彩在线| 久久久久久69| 永久久久久久久| 日本不卡免费一区| 亚洲人a成www在线影院| 成人在线电影网站| 日韩精品一区二区三区中文字幕 | 久久免费精品国产久精品久久久久| 成人性生交大片免费看视频直播 | 538在线一区二区精品国产| 男人揉女人奶房视频60分| av在线看片| 国产精品女主播av| 欧美一区二区三区综合| 黄色网址在线免费观看| 亚洲国产精品久久人人爱蜜臀| 潘金莲一级淫片aaaaaa播放1| yiren22亚洲综合伊人22| 亚洲另类一区二区| 日韩av播放器| 免费看男女www网站入口在线| 欧美主播一区二区三区| 蜜臀久久99精品久久久酒店新书| 奇米一区二区| 亚洲一区第一页| 性欧美一区二区| 国产精品a久久久久| 欧美精品在线观看91| 国产精品久久久久久久久久精爆| 亚洲小说欧美另类婷婷| 欧美激情在线观看视频| 中国女人真人一级毛片| 日韩国产精品91| 成人欧美一区二区三区黑人免费| 国产h在线观看| 中文字幕精品一区二区三区精品| 图片区小说区区亚洲五月| 懂色av中文在线| 欧美日韩国产在线播放| 又黄又色的网站| 欧美电影在线观看完整版| 日韩大陆欧美高清视频区| 中文字字幕码一二三区| 加勒比久久综合| 91成人在线观看国产| 亚洲国产日韩在线观看| 亚洲男帅同性gay1069| 小泽玛利亚视频在线观看| 免费观看不卡av| 色狠狠久久aa北条麻妃| 午夜免费激情视频| 在线日韩中文| 国产精品mp4| 国产精品成人无码| 国产一区二区三区免费观看| 日本一区二区在线视频| 色综合久久影院| 在线中文字幕不卡| av小说在线观看| 日韩精品dvd| 欧美激情一区二区三级高清视频 | 手机在线观看av网站| 亚洲高清一区二| 伊人久久综合视频| 99久久精品免费看| www黄色日本| 精品福利在线| 日韩免费视频线观看| 丰满圆润老女人hd| 久久高清一区| 91av免费看| 蜜桃成人在线视频| 亚洲视频一区二区在线观看| 最新免费av网址| 亚洲啊v在线观看| 欧美在线视频一区二区| 国产日产亚洲系列最新| 久久先锋资源网| 不卡av免费在线| 99精品美女| 99re国产在线播放| www日韩tube| 欧美美女bb生活片| 国产精品jizz| 毛片av一区二区三区| 激情伦成人综合小说| 黄色网在线免费看| 日韩视频中午一区| 亚洲激情图片网| 久久福利毛片| 正义之心1992免费观看全集完整版| 四虎国产精品免费久久| 亚洲欧美日韩区| 日韩男人的天堂| 久久久美女毛片| 黄色一级片在线看| 奇米色欧美一区二区三区| 91久久精品国产91久久| 东热在线免费视频| 日韩亚洲欧美一区| 800av免费在线观看| 成人精品免费看| 51xx午夜影福利| 亚洲色图丝袜| 亚洲最大成人免费视频| 老司机午夜在线| 亚洲成人激情在线观看| 亚洲 小说区 图片区| 一区二区三区欧美日韩| 一级黄色性视频| 久久九九免费| 黄色一级片av| 国产欧美日韩影院| 99久久无色码| 78精品国产综合久久香蕉| 亚洲人a成www在线影院| 性做久久久久久久久久| 在线观看日韩电影| 香蕉视频一区二区| 国产激情视频一区二区三区欧美| 国产免费毛卡片| 欧美在线网站| 成人3d动漫一区二区三区91| 写真福利精品福利在线观看| 欧美精品激情blacked18| 91ph在线| 欧美一三区三区四区免费在线看| av图片在线观看| 一区二区国产视频| 午夜精品久久久久99蜜桃最新版| 看电视剧不卡顿的网站| aa在线观看视频| 外国成人在线视频| 国产精品第8页| 91福利区在线观看| 精品视频在线播放| 亚洲精品毛片一区二区三区| 国产欧美一区二区三区在线老狼| 一本色道无码道dvd在线观看| 黄色av成人| 蜜桃狠狠色伊人亚洲综合网站| 欧美第一在线视频| 成人久久18免费网站图片| 欧美黄色三级| 青青草原成人在线视频| 1区2区3区在线| 久久久久久久久久av| av免费网站在线| 亚洲国产成人精品女人久久久| jlzzjlzzjlzz亚洲人| 91 com成人网| 国产男男gay体育生白袜| 欧美日韩国产在线观看| 久久国产免费观看| 久久一留热品黄| 亚洲av无码一区二区三区网址 | 久久免费国产视频| 日色在线视频| 日韩电影中文字幕一区| 蜜桃久久一区二区三区| 亚洲成人av中文字幕| 网站黄在线观看| 欧美日韩一区二区三区高清 | 999成人精品视频线3| 亚洲精品一品区二品区三品区| 国产精选久久| 欧美一级成年大片在线观看| 欧美日韩在线看片| 亚洲国产一区二区三区四区| 欧美综合视频在线| 日韩精品视频免费在线观看| 日本一级在线观看| 国产一区二区三区在线| 3d成人动漫在线| 久久精品影视伊人网| 欧美亚洲天堂| xxav国产精品美女主播| 四虎永久在线观看| 538prom精品视频线放| 精品欧美在线观看| 亚洲精品一区二区三区香蕉| 亚洲天堂久久久久| 欧美日韩国产专区| 激情网站在线观看| 欧美浪妇xxxx高跟鞋交| 亚洲h视频在线观看| 日韩国产中文字幕| 亚洲成a人v欧美综合天堂麻豆| 久久综合久久八八| 岛国大片在线观看| 日韩亚洲精品视频| 色yeye免费人成网站在线观看| 在线视频欧美性高潮| 亚洲人妻一区二区三区| 亚洲小视频在线观看| caoporn97在线视频| 98精品国产自产在线观看| 欧美色999| 999国产在线| 九九久久婷婷| 好吊色这里只有精品| 亚洲一区成人| 久久综合桃花网| 久久久www免费人成精品| 日本一级特级毛片视频| 精品久久久免费| 日韩三级视频在线| 欧美午夜一区二区三区| 亚洲av无码一区二区三区性色| 亚洲男人天堂九九视频| 日本视频在线播放| 51久久精品夜色国产麻豆| 亚洲国产aⅴ精品一区二区三区| 国产精品手机视频| 成人知道污网站| 99久久综合狠狠综合久久止 | 国产精品一区二区在线观看网站| 日韩在线xxx| 国产精品99久久久久久似苏梦涵| 右手影院亚洲欧美| 亚洲一区二区精品视频| 在线观看不卡的av| 日韩经典中文字幕| 日韩伦理av| 国产免费一区二区三区在线观看| 97欧美成人| 精品欧美一区二区久久久伦| 国产精品久久久久久久| 免费在线观看的av网站| 99精品国产在热久久婷婷| 国产午夜大地久久| 国产在线精品不卡| 久久久精品成人| 色狠狠一区二区三区香蕉| 蜜臀av免费在线观看| 色综合久久天天综线观看| 日韩五码电影| 亚洲黄色一区二区三区| 久久久久国产精品一区三寸| 毛茸茸free性熟hd| 亚洲免费资源在线播放| 亚洲一区二区视频在线播放| 尤物精品国产第一福利三区| 日韩精品黄色| 国产精品免费福利| 九九亚洲精品| 日本精品一区二区三区四区| 99久久久精品免费观看国产蜜| 久久久国产精品黄毛片| 欧美一区二区三区公司| 黄网站在线播放| 国产精自产拍久久久久久| blacked蜜桃精品一区| 99草草国产熟女视频在线| 久久99精品一区二区三区三区| 佐山爱在线视频| 亚洲视频 欧洲视频| 国产精品熟女久久久久久| 久久久精品在线| 国产精品视频一区二区三区| 法国空姐在线观看免费| 国产成人精品午夜视频免费| 欧美激情一区二区视频| 日韩欧美区一区二| 国产白丝在线观看| 国产精品久久久久久中文字| 欧美亚洲国产精品久久| 色多多视频在线播放| 国产精品久久777777| a v视频在线观看| 亚洲美女在线视频| 丝袜美腿一区| 国产精品推荐精品| 日韩一级不卡| 日本xxxxxxxxx18| 欧美日韩精品一二三区| 成人午夜在线影视| 国产日韩精品推荐| 久久久久久美女精品| 性生活一级大片| 亚洲v日本v欧美v久久精品| 伊人久久成人网| 久久亚洲精品一区| 国产精品对白| 激情图片qvod| 成人国产在线观看| 久久青青草原亚洲av无码麻豆 | 欧美肥胖老妇做爰| 青春草免费在线视频| 欧美日韩最好看的视频| 久久国产免费看| 日韩大片免费在线观看| 亚洲香蕉在线观看| 天堂久久av| 亚洲 中文字幕 日韩 无码| 亚洲欧洲在线观看av| 无码人妻丰满熟妇奶水区码| 精品国产一区二区精华| 午夜影视一区二区三区| 亚洲三区四区| 免费精品视频在线| 午夜少妇久久久久久久久| 亚洲精品美女久久| 四虎精品永久免费| 国产精品无码一区二区在线| 国产精品久久久久久久久免费相片| 亚洲国产精品久久人人爱潘金莲| 国产成人欧美在线观看| 国精品一区二区三区| 欧美日韩高清丝袜| 日韩精品一区二| 欧美综合社区国产| 人人妻人人添人人爽欧美一区|