一:Redis基本操做redis
基於RedisTemplate(Spring對操做Redis數據庫的封裝)對五種數據類型的操做數據庫
string類型 緩存
適用場景:通常的key-value緩存,計數功能的緩存。安全
list類型 服務器
適用場景: value存放的是結構化的對象,比較方便的就是操做其中的某個字段。博主在作單點登陸的時候,就是用這種數據結構存儲用戶信息,以cookieId做爲key,設置30分鐘爲緩存過時時間,能很好的模擬出相似session的效果。cookie
hash類型 session
使用場景:使用List的數據結構,能夠作簡單的消息隊列的功能。另外還有一個就是,能夠利用lrange命令,作基於redis的分頁功能,性能極佳,用戶體驗好。數據結構
set類型 多線程
使用場景: set堆放的是一堆不重複值的集合。因此能夠作全局去重的功能。爲何不用JVM自帶的Set進行去重?由於咱們的系統通常都是集羣部署,使用JVM自帶的Set,比較麻煩,難道爲了一個作一個全局去重,再起一個公共服務,太麻煩了。另外,就是利用交集、並集、差集等操做,能夠計算共同喜愛,所有的喜愛,本身獨有的喜愛等功能。架構
zset類型
使用場景: sorted set多了一個權重參數score,集合中的元素可以按score進行排列。能夠作排行榜應用,取TOP N操做。另外,參照另外一篇《分佈式之延時任務方案解析》,該文指出了sorted set能夠用來作延時任務。最後一個應用就是能夠作範圍查找。
常見的幾個問題
(一)緩存和數據庫雙寫一致性問題
獲取緩存的基本流程:
那麼有幾個問題出現:
1. 先操做緩存中的數據再更新數據庫的數據
2. 修改數據庫中的數據再操做緩存中的數據
3. 更新緩存仍是讓緩存失效
redis中的數據和數據庫中的數據不可能保證絕對事務性,這個是毫無疑問的,因此在實際應用中,咱們都是基於當前的場景進行權衡下降出現不一致問題的出現機率。更新緩存表示數據不但會寫入到數據庫,還會同步更新緩存,而讓緩存失效是表示只更新數據庫中的數據,而後刪除緩存中對應的key。那麼這兩種方式怎麼去選擇?
1. 若是更新緩存的代價很小,那麼能夠先更新緩存,這個代價很小的意思是不須要很複雜的計算。
2. 若是是更新緩存的代價很大,意味着須要經過多個接口調用和數據查詢才能得到最新的結果,那麼能夠先淘汰緩存。淘汰緩存之後後續的請求若是在緩存中找不到,天然去數據庫中檢索。
更新數據庫和更新緩存這兩個操做,是沒法保證原子性的,因此咱們須要根據當前業務的場景的容忍性來選擇。也就是若是出現不一致的狀況下,哪種更新方式對業務的影響最小,就先執行影響最小的方案。
(二)緩存雪崩問題
緩存同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到數據庫上,從而致使數據庫鏈接異常
1. 對緩存的訪問,若是發現從緩存中取不到值,那麼經過加鎖或者隊列的方式保證緩存的單進程操做,從而避免失效時併發請求所有落到底層的存儲系統上,可是這種方式會帶來性能上的損耗。
2. 將緩存失效的時間分散,下降每個緩存過時時間的重複率。
3. 若是是由於緩存服務器故障致使的問題,一方面須要保證緩存服務器的高可用、另外一方面,應用程序中能夠採用多級緩存。
(三)緩存擊穿問題
黑客故意去請求緩存中不存在的數據,致使全部的請求都懟到數據庫上,從而數據庫鏈接異常
1. 若是查詢數據庫也爲空,直接設置一個默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫,這種辦法最簡單粗暴。好比,」key」 , 「&&」。在返回這個&&值的時候,我 們的應用就能夠認爲這是不存在的key,那咱們的應用就能夠 決定是否繼續等待繼續訪問,仍是放棄掉此次操做。若是繼續等待訪問,過一個時間輪詢點後,再次請求這個key,若是取到的值再也不是&&,則能夠認爲這時候key有值了,從而避免了透傳到數據庫,從而把大量的相似請求擋在了緩存之中。
2. 根據緩存數據Key的設計規則,將不符合規則的key進行過濾採用布隆過濾器,將全部可能存在的數據哈希到一個足夠大的BitSet中,不存在的數據將會被攔截掉,從而避免了對底層存儲系統的查 詢壓力。