常見緩存問題處理-緩存穿透、緩存擊穿、緩存雪崩、大Key優化


參考:

https://blog.csdn.net/kongtiao5/article/details/82771694

https://www.cnblogs.com/xichji/p/11286443.html

https://blog.csdn.net/zeb_perfect/article/details/54135506

https://blog.csdn.net/huxianbo0807/article/details/102912172

https://blog.csdn.net/lavorange/article/details/83475960

 

 

 

 

緩存穿透、緩存擊穿、緩存雪崩區別和解決方案

一、緩存處理流程

      前台請求,后台先從緩存中取數據,取到直接返回結果,取不到時從數據庫中取,數據庫取到更新緩存,並返回結果,數據庫也沒取到,那直接返回空結果。

      

 

二、緩存穿透

       描述:

       緩存穿透是指緩存和數據庫中都沒有的數據,而用戶不斷發起請求,如發起為id為“-1”的數據或id為特別大不存在的數據。這時的用戶很可能是攻擊者,攻擊會導致數據庫壓力過大。

      解決方案:

  1. 接口層增加校驗,如用戶鑒權校驗,id做基礎校驗,id<=0的直接攔截;
  2. 從緩存取不到的數據,在數據庫中也沒有取到,這時也可以將key-value對寫為key-null,緩存有效時間可以設置短點,如30秒(設置太長會導致正常情況也沒法使用)。這樣可以防止攻擊用戶反復用同一個id暴力攻擊

 

三、緩存擊穿

      描述:

      緩存擊穿是指緩存中沒有但數據庫中有的數據(一般是緩存時間到期),這時由於並發用戶特別多,同時讀緩存沒讀到數據,又同時去數據庫去取數據,引起數據庫壓力瞬間增大,造成過大壓力

      解決方案:

  1. 設置熱點數據永遠不過期。
  2. 加互斥鎖,互斥鎖參考代碼如下:

         

 

          說明:

          1)緩存中有數據,直接走上述代碼13行后就返回結果了

         2)緩存中沒有數據,第1個進入的線程,獲取鎖並從數據庫去取數據,沒釋放鎖之前,其他並行進入的線程會等待100ms,再重新去緩存取數據。這樣就防止都去數據庫重復取數據,重復往緩存中更新數據情況出現。

          3)當然這是簡化處理,理論上如果能根據key值加鎖就更好了,就是線程A從數據庫取key1的數據並不妨礙線程B取key2的數據,上面代碼明顯做不到這點。

 

四、緩存雪崩

      描述:

      緩存雪崩是指緩存中數據大批量到過期時間,而查詢數據量巨大,引起數據庫壓力過大甚至down機。和緩存擊穿不同的是,緩存擊穿指並發查同一條數據,緩存雪崩是不同數據都過期了,很多數據都查不到從而查數據庫。

     解決方案:

  1. 緩存數據的過期時間設置隨機,防止同一時間大量數據過期現象發生
  2. 如果緩存數據庫是分布式部署,將熱點數據均勻分布在不同搞得緩存數據庫中
  3. 設置熱點數據永遠不過期。

 

 

 

 

 

REDIS緩存穿透,緩存擊穿,緩存雪崩原因+解決方案

一、前言

在我們日常的開發中,無不都是使用數據庫來進行數據的存儲,由於一般的系統任務中通常不會存在高並發的情況,所以這樣看起來並沒有什么問題,可是一旦涉及大數據量的需求,比如一些商品搶購的情景,或者是主頁訪問量瞬間較大的時候,單一使用數據庫來保存數據的系統會因為面向磁盤,磁盤讀/寫速度比較慢的問題而存在嚴重的性能弊端,一瞬間成千上萬的請求到來,需要系統在極短的時間內完成成千上萬次的讀/寫操作,這個時候往往不是數據庫能夠承受的,極其容易造成數據庫系統癱瘓,最終導致服務宕機的嚴重生產問題。

為了克服上述的問題,項目通常會引入NoSQL技術,這是一種基於內存的數據庫,並且提供一定的持久化功能。

redis技術就是NoSQL技術中的一種,但是引入redis又有可能出現緩存穿透,緩存擊穿,緩存雪崩等問題。本文就對這三種問題進行較深入剖析。

二、初認識

  • 緩存穿透:key對應的數據在數據源並不存在,每次針對此key的請求從緩存獲取不到,請求都會到數據源,從而可能壓垮數據源。比如用一個不存在的用戶id獲取用戶信息,不論緩存還是數據庫都沒有,若黑客利用此漏洞進行攻擊可能壓垮數據庫。
  • 緩存擊穿:key對應的數據存在,但在redis中過期,此時若有大量並發請求過來,這些請求發現緩存過期一般都會從后端DB加載數據並回設到緩存,這個時候大並發的請求可能會瞬間把后端DB壓垮。
  • 緩存雪崩:當緩存服務器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,也會給后端系統(比如DB)帶來很大壓力。

三、緩存穿透解決方案

一個一定不存在緩存及查詢不到的數據,由於緩存是不命中時被動寫的,並且出於容錯考慮,如果從存儲層查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到存儲層去查詢,失去了緩存的意義。

有很多種方法可以有效地解決緩存穿透問題最常見的則是采用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被 這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。另外也有一個更為簡單粗暴的方法(我們采用的就是這種),如果一個查詢返回的數據為空(不管是數據不存在,還是系統故障),我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過五分鍾。

粗暴方式偽代碼:

//偽代碼 public object GetProductListNew() { int cacheTime = 30; String cacheKey = "product_list"; String cacheValue = CacheHelper.Get(cacheKey); if (cacheValue != null) { return cacheValue; } cacheValue = CacheHelper.Get(cacheKey); if (cacheValue != null) { return cacheValue; } else { //數據庫查詢不到,為空 cacheValue = GetProductListFromDB(); if (cacheValue == null) { //如果發現為空,設置個默認值,也緩存起來 cacheValue = string.Empty; } CacheHelper.Add(cacheKey, cacheValue, cacheTime); return cacheValue; } }

四、緩存擊穿解決方案

key可能會在某些時間點被超高並發地訪問,是一種非常“熱點”的數據。這個時候,需要考慮一個問題:緩存被“擊穿”的問題。

使用互斥鎖(mutex key)

業界比較常用的做法,是使用mutex。簡單地來說,就是在緩存失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操作返回成功時,再進行load db的操作並回設緩存;否則,就重試整個get緩存的方法。

SETNX,是「SET if Not eXists」的縮寫,也就是只有不存在的時候才設置,可以利用它來實現鎖的效果。

public String get(key) { String value = redis.get(key); if (value == null) { //代表緩存值過期 //設置3min的超時,防止del操作失敗的時候,下次緩存過期一直不能load db if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表設置成功 value = db.get(key); redis.set(key, value, expire_secs); redis.del(key_mutex); } else { //這個時候代表同時候的其他線程已經load db並回設到緩存了,這時候重試獲取緩存值即可 sleep(50); get(key); //重試 } } else { return value; } }

memcache代碼:

if (memcache.get(key) == null) { // 3 min timeout to avoid mutex holder crash if (memcache.add(key_mutex, 3 * 60 * 1000) == true) { value = db.get(key); memcache.set(key, value); memcache.delete(key_mutex); } else { sleep(50); retry(); } }

其它方案:待各位補充。

五、緩存雪崩解決方案

與緩存擊穿的區別在於這里針對很多key緩存,前者則是某一個key。

緩存正常從Redis中獲取,示意圖如下:
redis1.md

緩存失效瞬間示意圖如下:
redis2.md

緩存失效時的雪崩效應對底層系統的沖擊非常可怕!大多數系統設計者考慮用加鎖或者隊列的方式保證來保證不會有大量的線程對數據庫一次性進行讀寫,從而避免失效時大量的並發請求落到底層存儲系統上。還有一個簡單方案就時講緩存失效時間分散開,比如我們可以在原有的失效時間基礎上增加一個隨機值,比如1-5分鍾隨機,這樣每一個緩存的過期時間的重復率就會降低,就很難引發集體失效的事件。

加鎖排隊,偽代碼如下:

//偽代碼 public object GetProductListNew() { int cacheTime = 30; String cacheKey = "product_list"; String lockKey = cacheKey; String cacheValue = CacheHelper.get(cacheKey); if (cacheValue != null) { return cacheValue; } else { synchronized(lockKey) { cacheValue = CacheHelper.get(cacheKey); if (cacheValue != null) { return cacheValue; } else { //這里一般是sql查詢數據 cacheValue = GetProductListFromDB(); CacheHelper.Add(cacheKey, cacheValue, cacheTime); } } return cacheValue; } }

加鎖排隊只是為了減輕數據庫的壓力,並沒有提高系統吞吐量。假設在高並發下,緩存重建期間key是鎖着的,這是過來1000個請求999個都在阻塞的。同樣會導致用戶等待超時,這是個治標不治本的方法!

注意:加鎖排隊的解決方式分布式環境的並發問題,有可能還要解決分布式鎖的問題;線程還會被阻塞,用戶體驗很差!因此,在真正的高並發場景下很少使用!

隨機值偽代碼:

//偽代碼 public object GetProductListNew() { int cacheTime = 30; String cacheKey = "product_list"; //緩存標記 String cacheSign = cacheKey + "_sign"; String sign = CacheHelper.Get(cacheSign); //獲取緩存值 String cacheValue = CacheHelper.Get(cacheKey); if (sign != null) { return cacheValue; //未過期,直接返回 } else { CacheHelper.Add(cacheSign, "1", cacheTime); ThreadPool.QueueUserWorkItem((arg) -> { //這里一般是 sql查詢數據 cacheValue = GetProductListFromDB(); //日期設緩存時間的2倍,用於臟讀 CacheHelper.Add(cacheKey, cacheValue, cacheTime * 2); }); return cacheValue; } } 

解釋說明:

  • 緩存標記:記錄緩存數據是否過期,如果過期會觸發通知另外的線程在后台去更新實際key的緩存;
  • 緩存數據:它的過期時間比緩存標記的時間延長1倍,例:標記緩存時間30分鍾,數據緩存設置為60分鍾。這樣,當緩存標記key過期后,實際緩存還能把舊數據返回給調用端,直到另外的線程在后台更新完成后,才會返回新緩存。

關於緩存崩潰的解決方法,這里提出了三種方案:使用鎖或隊列、設置過期標志更新緩存、為key設置不同的緩存失效時間,還有一種被稱為“二級緩存”的解決方法。

六、小結

針對業務系統,永遠都是具體情況具體分析,沒有最好,只有最合適。

於緩存其它問題,緩存滿了和數據丟失等問題,大伙可自行學習。最后也提一下三個詞LRU、RDB、AOF,通常我們采用LRU策略處理溢出,Redis的RDB和AOF持久化策略來保證一定情況下的數據安全。

參考相關鏈接:

https://blog.csdn.net/zeb_perfect/article/details/54135506
https://blog.csdn.net/fanrenxiang/article/details/80542580
https://baijiahao.baidu.com/s?id=1619572269435584821&wfr=spider&for=pc
https://blog.csdn.net/xlgen157387/article/details/79530877

視頻資源獲取,可直進百度雲群:

https://pan.baidu.com/mbox/homepage?short=btNBJoN

本文在米兜公眾號鏈接

https://mp.weixin.qq.com/s/ksVC1049wZgPIOy2gGziNA

 

 

 

 

 

 

 

 

緩存雪崩問題及處理方案

一、什么是緩存雪崩

    緩存雪崩就是指緩存由於某些原因(比如 宕機、cache服務掛了或者不響應)整體crash掉了, 導致大量請求到達后端數據庫,從而導致數據庫崩潰,整個系統崩潰,發生災難
 
下面的就是一個雪崩的簡單過程:
1、redis集群徹底崩潰
2、緩存服務大量對redis的請求hang住,占用資源
3、緩存服務大量的請求打到源頭服務去查詢mysql,直接打死mysql
4、源頭服務因為mysql被打死也崩潰,對源服務的請求也hang住,占用資源
5、緩存服務大量的資源全部耗費在訪問redis和源服務無果,最后自己被拖死,無法提供服務
6、nginx無法訪問緩存服務,redis和源服務,只能基於本地緩存提供服務,但是緩存過期后,沒有數據提供
7、網站崩潰
 
雪崩問題在國外叫做:stampeding herd(奔逃的野牛),指的的cache crash后,流量會像奔逃的野牛一樣,打向后端。
 
 
 
導致這種現象可能的原因:
1、例如 “緩存並發”,“緩存穿透”,“緩存顛簸” 等問題,這些問題也可能會被惡意攻擊者所利用。
2、例如 某個時間點內,系統預加載的緩存周期性集中失效了。解決方法:可以通過設置不同的過期時間,來錯開緩存過期,從而避免緩存集中失效。
 
 
二、預防和解決緩存雪崩問題
1) 事前解決方案
  • 保證緩存層服務高可用性
和飛機都有多個引擎一樣,如果緩存層設計成高可用的,即使個別節點、個別機器、甚至是機房宕掉,依然可以提供服務,例如 Redis Sentinel 和 Redis Cluster 都實現了高可用。
部署方式一:雙機房部署,一套Redis Cluster,部分機器在一個機房,另一部分機器在另外一個機房。
部署方式二:雙機房部署,兩套Redis Cluster,兩套Redis Cluster之間做一個數據同步。
 
 
2) 事中解決方案
  • 對緩存訪問進行資源隔離(熔斷)、Fail Silent 降級
避免所有資源hang在訪問緩存上,當判斷緩存出現問題, 則自動進行熔斷並按預設進行降級操作
 
  • ehcache本地緩存
應對零散的緩存中數據被清除掉的現象,另外一個主要預防緩存徹底崩潰,ehcache的緩存還能支撐一陣。
 
 
  • 對源服務訪問進行限流、資源隔離(熔斷)、Stubbed 降級
無論是緩存層還是存儲層都會有出錯的概率,可以將它們視同為資源。作為並發量較大的系統, 假如有一個資源不可用,可能會造成線程全部 hang 在這個資源上,造成整個系統不可用
相信大家一定遇到過這樣的頁面:這些應該就是淘寶的降級策略。
 
降級在高並發系統中是非常正常的:比如推薦服務中,如果個性化推薦服務不可用,可以降級補充熱點數據,不至於造成前端頁面是開天窗。
 
在實際項目中,我們需要對重要的資源 ( 例如 Redis、 MySQL、 Hbase、外部接口 ) 都進行隔離, 讓每種資源都單獨運行在自己的線程池中,即使個別資源出現了問題,對其他服務沒有影響。但是線程池如何管理,比如如何關閉資源池,開啟資源池,資源池閥值管理,這些做起來還是相當復雜的,這里推薦一個 Java 依賴隔離工具 Hystrix(https://github.com/Netflix/Hystrix)。
 
 
3)事后解決方案
  • Redis數據備份和恢復
  • 快速緩存預熱
 
 
4) 提前演練
在項目上線前,演練緩存層宕掉后,應用以及后端的負載情況以及可能出現的問題,在此基礎上做一些預案設定。

 

 

 

 

 

 

 

 

 

 

 

 

如何解決Redis緩存雪崩、緩存穿透、緩存並發等5大難題

01.緩存雪崩

數據未加載到緩存中,或者緩存同一時間大面積的失效,從而導致所有請求都去查數據庫,導致數據庫CPU和內存負載過高,甚至宕機。

比如一個雪崩的簡單過程:

1、redis集群大面積故障

2、緩存失效,但依然大量請求訪問緩存服務redis

3、redis大量失效后,大量請求轉向到mysql數據庫

4、mysql的調用量暴增,很快就扛不住了,甚至直接宕機

5、由於大量的應用服務依賴mysql和redis的服務,這個時候很快會演變成各服務器集群的雪崩,***網站徹底崩潰。

02.緩存雪崩解決方案

1.緩存的高可用性

緩存層設計成高可用,防止緩存大面積故障。即使個別節點、個別機器、甚至是機房宕掉,依然可以提供服務,例如 Redis Sentinel 和 Redis Cluster 都實現了高可用。

2.緩存降級

可以利用ehcache等本地緩存(暫時使用),但主要還需要對源服務訪問進行限流、資源隔離(熔斷)、降級等。

當訪問量劇增、服務出現問題仍然需要保證服務還是可用的。系統可以根據一些關鍵數據進行自動降級,也可以配置開關實現人工降級,這里會涉及到運維的配合。

降級的最終目的是保證核心服務可用,即使是有損的。

比如我的淘寶頁面,由於是非核心頁面,后端服務如果暫時不能提供使用的情況,可以考慮直接使用一個靜態頁面替換掉,這樣對於用戶也是永遠提供服務的狀態(再發報警信息提示急需解決),也不至於出現空白或者異常錯誤的裸奔狀態。

在進行降級之前要對系統進行梳理,比如:哪些業務是核心(必須保證),哪些業務可以容許暫時不提供服務(利用靜態頁面替換)等,以及配合服務器核心指標,來后設置整體預案,比如:

(1)一般:比如有些服務偶爾因為網絡抖動或者服務正在上線而超時,可以自動降級;

(2)警告:有些服務在一段時間內成功率有波動(如在95~100%之間),可以自動降級或人工降級,並發送告警;

(3)錯誤:比如可用率低於90%,或者數據庫連接池被打爆了,或者訪問量突然猛增到系統能承受的***閥值,此時可以根據情況自動降級或者人工降級;

(4)嚴重錯誤:比如因為特殊原因數據錯誤了,此時需要緊急人工降級。

3.Redis備份和快速預熱

1)Redis數據備份和恢復

2)快速緩存預熱

3).提前演練

***,建議還是在項目上線前,演練緩存層宕掉后,應用以及后端的負載情況以及可能出現的問題,對高可用提前預演,提前發現問題。

03.緩存穿透

緩存穿透是指查詢一個一不存在的數據。例如:從緩存redis沒有***,需要從mysql數據庫查詢,查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到數據庫去查詢,造成緩存穿透。

解決思路:

如果查詢數據庫也為空,直接設置一個默認值存放到緩存,這樣第二次到緩沖中獲取就有值了,而不會繼續訪問數據庫。設置一個過期時間或者當有值的時候將緩存中的值替換掉即可。

可以給key設置一些格式規則,然后查詢之前先過濾掉不符合規則的Key。

04.緩存並發

這里的並發指的是多個redis的client同時set key引起的並發問題。其實redis自身就是單線程操作,多個client並發操作,按照先到先執行的原則,先到的先執行,其余的阻塞。當然,另外的解決方案是把redis.set操作放在隊列中使其串行化,必須的一個一個執行。

05.緩存預熱

緩存預熱就是系統上線后,將相關的緩存數據直接加載到緩存系統。

這樣就可以避免在用戶請求的時候,先查詢數據庫,然后再將數據緩存的問題,用戶直接查詢事先被預熱的緩存數據。

解決思路:

1、直接寫個緩存刷新頁面,上線時手工操作下

2、數據量不大,可以在項目啟動的時候自動進行加載

目的就是在系統上線前,將數據加載到緩存中。

 

 

 

 

Redis大Key優化

最近在使用redis存儲數據的時候造成了大key的問題,被運維同學挑戰,所謂的大key就是存儲本身的key值空間太大,或者hash,list,set等存儲中value值過多。

業務場景:

       即通過hash的方式來存儲每一天用戶訂單次數。那么key = order_20181010, field = order_id, value = 10。那么如果一天有百萬千萬甚至上億訂單的時候,key后面的值是很多,存儲空間也很大,造成所謂的大key。

大key的風險:
1.讀寫大key會導致超時嚴重,甚至阻塞服務

2.如果刪除大key,DEL命令可能阻塞Redis進程數十秒,使得其他請求阻塞,對應用程序和Redis集群可用性造成嚴重的影響

3.建議每個key不要超過M級別。

 

簡單的解決問題:

將大key進行分割,為了均勻分割,可以對field進行hash並通過質數N取余,將余數加到key上面,我們取質數N為997。

那么新的key則可以設置為:

newKey = order_20181010_String.valueOf( Math.abs(order_id.hashcode() % 997) )

field = order_id

value = 10

hset (newKey, field, value) ;  

hget(newKey, field)

 

 

 

 

 

 

Redis Value過大問題 鍵值過大

Redis Big Key問題

數據量大的 key ,由於其數據大小遠大於其他key,導致經過分片之后,某個具體存儲這個 big key 的實例內存使用量遠大於其他實例,造成內存不足,拖累整個集群的使用。big key 在不同業務上,通常體現為不同的數據,比如:

  1. 論壇中的大型持久蓋樓活動;
  2. 聊天室系統中熱門聊天室的消息列表;

帶來的問題

bigkey 通常會導致內存空間不平衡,超時阻塞,如果 key 較大,redis 又是單線程,操作 bigkey 比較耗時,那么阻塞 redis 的可能性增大。每次獲取 bigKey 的網絡流量較大,假設一個 bigkey 為 1MB,每秒訪問量為 1000,那么每秒產生 1000MB 的流量,對於普通千兆網卡,按照字節算 128M/S 的服務器來說可能扛不住。而且一般服務器采用單機多實例方式來部署,所以還可能對其他實例造成影響。

  1. 如果是集群模式下,無法做到負載均衡,導致請求傾斜到某個實例上,而這個實例的QPS會比較大,內存占用也較多;對於Redis單線程模型又容易出現CPU瓶頸,當內存出現瓶頸時,只能進行縱向庫容,使用更牛逼的服務器。
  2. 涉及到大key的操作,尤其是使用hgetall、lrange、get、hmget 等操作時,網卡可能會成為瓶頸,也會到導致堵塞其它操作,qps 就有可能出現突降或者突升的情況,趨勢上看起來十分不平滑,嚴重時會導致應用程序連不上,實例或者集群在某些時間段內不可用的狀態。
  3. 假如這個key需要進行刪除操作,如果直接進行DEL 操作,被操作的實例會被Block住,導致無法響應應用的請求,而這個Block的時間會隨着key的變大而變長。

什么是 big key

  1. 字符串類型:一般認為超過 10k 的就是 bigkey,但是這個值和具體的 OPS 相關。
  2. 非字符串類型:體現在哈希,列表,集合類型元素過多。

尋找big key

  1. redis-cli自帶--bigkeys

    1
    2
    
    $ redis-cli -p 999 --bigkeys -i 0.1
    #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).
    
  2. 獲取生產Redis的rdb文件,通過rdbtools分析rdb生成csv文件,再導入MySQL或其他數據庫中進行分析統計,根據size_in_bytes統計bigkey

    1
    2
    3
    4
    
    $ git clone https://github.com/sripathikrishnan/redis-rdb-tools
    $ cd redis-rdb-tools
    $ sudo python setup.py install
    $ rdb -c memory dump-10030.rdb > memory.csv
    
  3. 通過python腳本,迭代scan key,每次scan 1000,對掃描出來的key進行類型判斷,例如:string長度大於10K,list長度大於10240認為是big bigkeys

  4. 其他第三方工具,例如:redis-rdb-cli

優化big key

優化big key的原則就是string減少字符串長度,list、hash、set、zset等減少成員數。

  1. string類型的big key,建議不要存入redis,用文檔型數據庫MongoDB代替或者直接緩存到CDN上等方式優化。有些 key 不只是訪問量大,數據量也很大,這個時候就要考慮這個 key 使用的場景,存儲在redis集群中是否是合理的,是否使用其他組件來存儲更合適;如果堅持要用 redis 來存儲,可能考慮遷移出集群,采用一主一備(或1主多備)的架構來存儲。

  2. 單個簡單的key存儲的value很大

    該對象需要每次都整存整取: 可以嘗試將對象分拆成幾個key-value, 使用multiGet獲取值,這樣分拆的意義在於分拆單次操作的壓力,將操作壓力平攤到多個redis實例中,降低對單個redis的IO影響
    該對象每次只需要存取部分數據: 可以像第一種做法一樣,分拆成幾個key-value,也可以將這個存儲在一個hash中,每個field代表一個具體的屬性,使用hget,hmget來獲取部分的value,使用hset,hmset來更新部分屬性。

  3. hash, set,zset,list 中存儲過多的元素

    可以將這些元素分拆。以hash為例,原先的正常存取流程是 hget(hashKey, field) ; hset(hashKey, field, value)
    現在,固定一個桶的數量,比如 10000, 每次存取的時候,先在本地計算field的hash值,模除 10000,確定了該field落在哪個key上。

1
2
3
newHashKey  =  hashKey + (hash(field) % 10000);   
hset(newHashKey, field, value) ;  
hget(newHashKey, field)

set, zset, list 也可以類似上述做法。但有些不適合的場景,比如,要保證 lpop 的數據的確是最早push到list中去的,這個就需要一些附加的屬性,或者是在 key的拼接上做一些工作(比如list按照時間來分拆)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM