分析:一致性問題是分布式常見問題,還可以再分為最終一致性和強一致性。資料庫和快取雙寫,就必然會存在不一致的問題。答這個問題,先明白乙個前提。就是如果對資料有強一致性要求,不能放快取。我們所做的一切,只能保證最終一致性。另外,我們所做的方案其實從根本上來說,只能說降低不一致發生的概率,無法完全避免。因此,有強一致性要求的資料,不能放快取。
首先,採取正確更新策略,先更新資料庫,再刪快取。其次,因為可能存在刪除快取失敗的問題,提供乙個補償措施即可,例如利用訊息佇列。
快取穿透,即黑客故意去請求快取中不存在的資料,導致所有的請求都懟到資料庫上,從而資料庫連線異常。
解決方案:
(一)利用互斥鎖,快取失效的時候,先去獲得鎖,得到鎖了,再去請求資料庫。沒得到鎖,則休眠一段時間重試
(二)採用非同步更新策略,無論key是否取到值,都直接返回。value值中維護乙個快取失效時間,快取如果過期,非同步起乙個執行緒去讀資料庫,更新快取。需要做快取預熱(專案啟動前,先載入快取)操作。
(三)提供乙個能迅速判斷請求是否有效的攔截機制,比如,利用布隆過濾器,內部維護一系列合法有效的key。迅速判斷出,請求所攜帶的key是否合法有效。如果不合法,則直接返回。
快取雪崩,即快取同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到資料庫上,從而導致資料庫連線異常。
解決方案:
(一)給快取的失效時間,加上乙個隨機值,避免集體失效。
(二)使用互斥鎖,但是該方案吞吐量明顯下降了。
(三)雙快取。我們有兩個快取,快取a和快取b。快取a的失效時間為20分鐘,快取b不設失效時間。自己做快取預熱操作。然後細分以下幾個小點
i 從快取a讀資料庫,有則直接返回
ii a沒有資料,直接從b讀資料,直接返回,並且非同步啟動乙個更新執行緒。
iii 更新執行緒同時更新快取a和快取b。
(1)如果對這個key操作,不要求順序
這種情況下,準備乙個分布式鎖,大家去搶鎖,搶到鎖就做set操作即可,比較簡單。
(2)如果對這個key操作,要求順序
假設有乙個key1,系統a需要將key1設定為valuea,系統b需要將key1設定為valueb,系統c需要將key1設定為valuec.
期望按照key1的value值按照 valuea–>valueb–>valuec的順序變化。這種時候我們在資料寫入資料庫的時候,需要儲存乙個時間戳。假設時間戳如下
系統a key 1
系統b key 1
系統c key 1
那麼,假設這會系統b先搶到鎖,將key1設定為。接下來系統a搶到鎖,發現自己的valuea的時間戳早於快取中的時間戳,那就不做set操作了。以此類推。
其他方法,比如利用佇列,將set方法變成序列訪問也可以。總之,靈活變通。
redis效能瓶頸一般體現在兩個地方
1.機器記憶體大小,因為redis的資料放在記憶體裡,所以存放資料量的多少取決於記憶體的多少
2.網路頻寬
redis客戶端執行一條命令分為如下四個過程:
1)傳送命令
2)命令排隊
3)命令執行
4)返回結果
其中1)+4)稱為round trip time(rtt,往返時間)。
redis的客戶端和服務端可能部署在不同的機器上。例如客戶端在北京,redis服務端在上海,兩地直線距離約為1300公里,那麼1次rtt時間=1300×2/(300000×2/3)=13毫秒(光在真空中傳輸速度為每秒30萬公里,這裡假設光纖為光速的2/3),那麼客戶端在1秒內大約只能執行80次左右的命令,這個和redis的高併發高吞吐特性背道而馳
所以要麼就在全國各地都有自己的redis伺服器,然後就近訪問,要麼就使用pipeline
pipeline(流水線)機制能改善上面這類問題,它能將一組redis命令進行組裝,通過一次rtt傳輸給redis,再將這組redis命令的執行結果按順序192返回給客戶端,下圖為沒有使用pipeline執行了n條命令,整個過程需要n次rtt
沒有pipeline執行n次命令模型
pipeline並不是什麼新的技術或機制,很多技術上都使用過。而且rtt在不同網路環境下會有不同,例如同機房和同機器會比較快,跨機房跨地區會比較慢。redis命令真正執行的時間通常在微秒級別,所以才會有redis效能瓶頸是網路這樣的說法。
但大部分開發人員更傾向於使用高階語言客戶端中的pipeline,目前大部分redis客戶端都支援pipeline
redis相關技術總結
1.一致性雜湊分割槽 一致性雜湊的目的就是為了在節點數目發生改變時盡可能少的遷移資料,將所有的儲存節點排列在收尾相接的hash環上,每個key在計算hash 後會順時針找到臨接的儲存節點存放。而當有節點加入或退 時,僅影響該節點在hash環上順時針相鄰的後續節點。優點加入和刪除節點只影響雜湊環中順時...
Redis總結(二)C 中如何使用redis
redis官網提供了很多開源的c 客戶端。例如,nhiredis servicestack.redis stackexchange.redis等。其中servicestack.redis應該算是比較流行的。它提供了一整套從redis資料結構都強型別物件轉換的機制並將物件json序列化。所以這裡只介紹...
Redis總結(二)C 中如何使用redis
redis官網提供了很多開源的c 客戶端。例如,nhiredis servicestack.redis stackexchange.redis等。其中servicestack.redis應該算是比較流行的。它提供了一整套從redis資料結構都強型別物件轉換的機制並將物件json序列化。所以這裡只介紹...