redis緩存與數據一致性


緩存

redis除了可以作為db存儲用,還有一些場景是做二級緩存(比如mysql+redis或者mysql+memcached),所以這里總結下作為緩存時需要考慮的一些問題及解決方案

緩存穿透

  • 名詞解釋:即黑客故意去請求緩存中不存在的數據,導致所有的請求都懟到數據庫上,從而數據庫連接異常。
  • 解決方案:
    (一)利用互斥鎖,緩存失效的時候,先去獲得鎖,得到鎖了,再去請求數據庫。沒得到鎖,則休眠一段時間重試
    (二)采用異步更新策略,無論key是否取到值,都直接返回。value值中維護一個緩存失效時間,緩存如果過期,異步起一個線程去讀數據庫,更新緩存。需要做緩存預熱(項目啟動前,先加載緩存)操作。
    (三)提供一個能迅速判斷請求是否有效的攔截機制,比如,利用布隆過濾器,內部維護一系列合法有效的key。迅速判斷出,請求所攜帶的Key是否合法有效。如果不合法,則直接返回。

緩存雪崩(緩存失效)

  • 名詞解釋:即緩存同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到數據庫上,從而導致數據庫連接異常。
  • 解決方案:
    (一)給緩存的失效時間,加上一個隨機值,避免集體失效。
    (二)使用互斥鎖,但是該方案吞吐量明顯下降了。
    (三)雙緩存。我們有兩個緩存,緩存A和緩存B。緩存A的失效時間為20分鍾,緩存B不設失效時間。自己做緩存預熱操作。然后細分以下幾個小點
    ● I 先從緩存A讀數據,有則直接返回;
    ● II A沒有數據,直接從B讀數據,直接返回,並且異步啟動一個更新線程;
    ● III 更新線程同時更新緩存A和緩存B。

緩存擊穿(熱點key)

  • 名詞解釋:是指一個key非常熱點,在不停的扛着大並發,大並發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大並發就穿破緩存,直接請求數據庫,就像在一個屏障上鑿開了一個洞。
  • 解決方案:
    (一)使用互斥鎖(mutex key):先去獲得鎖,得到鎖后構建緩存,其他線程等待構建緩存的線程執行完,重新從緩存獲取數據就可以了;
    (二)"提前"使用互斥鎖:在value內部設置1個超時值(timeout1), timeout1比實際的timeout(timeout2)小。當從cache讀取到timeout1發現它已經過期,馬上延長timeout1並重新設置到cache。然后再從數據庫加載數據並設置到cache中;
    (三)永不過期:沒有設置過期時間就保證不會出現熱點key過期問題
    (四)資源保護:做資源的隔離保護主線程池

緩存並發競爭(並發set)

  • 名詞解釋:多個client線程同時set key引起的並發問題
  • 解決方案:
    (一)分布式鎖+時間戳:准備一個分布式鎖(SETNX實現),大家去搶鎖,搶到鎖就做set操作,value需要保存一個時間戳判斷set順序;搶到鎖的線程的時間戳早於緩存中的時間戳就不做set操作。
    (二)消息隊列:把Redis.set操作放在隊列中使其串行化,必須的一個一個執行。這種方式在一些高並發的場景中算是一種通用的解決方案。

數據一致性

當一份數據存在多個數據源(比如mysql+redis)或者多個redis實例(redis cluster模式下)時需要考慮其最終一致性問題,避免臟讀。

緩存(雙寫)一致性

雙寫一致性1
1)線程A發起一個寫操作,第一步write DB
2)線程A第二步del cache
3)線程B發起一個讀操作,cache miss
4)線程B從DB獲取最新數據
5)線程B同時set cache


雙寫一致性2
1)讀取緩存中是否有相關數據
2)如果緩存中有相關數據value,則返回
3)如果緩存中沒有相關數據,則從數據庫讀取相關數據放入緩存中key->value,再返回
4)如果有更新數據,則先更新數據,再刪除緩存
5)為了保證第四步刪除緩存成功,使用binlog異步刪除
6)如果是主從數據庫,binglog取自於從庫
7)如果是一主多從,每個從庫都要采集binlog,然后消費端收到最后一台binlog數據才刪除緩存

Redis集群(Redis-cluster)一致性原理

哨兵(Sentinel)模式

Sentinel 是 Redis 高可用的解決方案,由一個或者多個 Sentinel 實例組成的系統可以監視 Redis 主節點及其從節點,當檢測到 Redis 主節點下線時,會根據特定的選舉規則從該主節點對應的所有從節點中選舉出一個“最優”的從節點升主,然后由升主的新主節點處理請求。

Redis集群產生的背景

單實例 Redis 雖然簡單,但瓶頸明顯。一是容量問題,在一些應用場景下,數據規模可達數十 G,甚至數百G,而物理機的資源卻是有限的,內存無法無限擴充;二是並發性能問題,Redis 號稱單實例10萬並發,但也僅僅是10萬並發。鑒於單機模式的局限性,歷時三年,Redis-Cluster應運而生。

Redis-cluster特點

節點互通:所有的Redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬;
去中心化:Redis-Cluster不存在中心節點,每個節點都記錄有集群的狀態信息,並且通過Gossip協議,使每個節點記錄的信息實現最終一致性;
客戶端直連:客戶端與Redis節點直連,不需要中間proxy層,客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可;
數據分片: Redis-Cluster的鍵空間被分割為 16384 個slot,這些slot被分別指派給主節點,當存儲Key-Value 時,根據 CRC16(key) Mod 16384的值,決定將一個 Key-value 放到哪個 Slot 中;
多數派原則:對於集群中的任何一個節點,需要超過半數的節點檢測到它失效(pFail),才會將其判定為失效(Fail);
自動Failover:當集群中某個主節點故障后(Fail),其它主節點會從故障主節點的從節點中選舉一個”最佳“從節點升主,替代故障的主節點;
功能弱化:集群模式下,由於數據分布在多個節點,不支持單機模式下的集合操作,也不支持多數據庫功能,集群只能使用默認的0號數據庫
集群規模:官方推薦的最大節點數量為 1000 個左右,這是因為當集群規模過大時,Gossip協議的效率會顯著下降,通信成本劇增;

分布式一致性hash(Consistent hashing)

哈希函數H(CRC32)的值空間為0-2^32-1(即哈希值是一個32位無符號整形)
整個空間按順時針方向組織,圓環的正上方的點代表0,0點右側的第一個點代表1,以此類推,2、3、4、5、6…
下一步將各個服務器使用Hash進行一個哈希,具體可以選擇服務器的IP或主機名作為關鍵字進行哈希,這樣每台機器就能確定其在哈希環上的位置.
將數據key使用相同的函數Hash計算出哈希值,並確定此數據在環上的位置,從此位置沿環順時針“行走”,第一台遇到的服務器就是其應該定位到的服務器.
一般的,在一致性Hash算法中,如果一台服務器增刪,則受影響的數據僅僅是此服務器到其環空間中前一台服務器(即沿着逆時針方向行走遇到的第一台服務器)之間數據,其它不會受到影響

為了解決數據傾斜問題(被緩存的對象大部分集中緩存在某一台服務器上),一致性Hash算法引入了虛擬節點機制,即對每一個服務節點計算多個哈希,每個計算結果位置都放置一個此服務節點,稱為虛擬節點。具體做法可以在服務器IP或主機名的后面增加編號來實現。在實際應用中,通常將虛擬節點數設置為32甚至更大,因此即使很少的服務節點也能做到相對均勻的數據分布。

pdn

附錄


免責聲明!

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



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