使用Redis做爲高速緩存

Redis適合哪些業務場景
常規業務系統的數據庫訪問中,讀寫操做的比例通常在7/3到9/1,也就是說讀操做遠多於寫操做,所以高併發系統設計裏,經過NoSQL技術將熱點數據(短時間內變更機率小的數據)放入內存以達到減輕DB壓力,提高數據訪問速度的目的,Redis和MongoDB是當下應用最普遍的NoSQL產品,固然若是系統裏的寫操做居多,也沒有必要使用緩存,所以Redis主要用於解決訪問性能和併發能力的問題。除了純數據緩存的做用以外,得益於其超高速的響應能力,Redis也經常使用於提供分佈式鎖的解決方案。redis

 

哪些設計思路保證了Redis高性能
單個Redis server對請求的處理是基於單線程工做模型的,但因爲是純內存操做,而且單線程的工做模式避免了線程上下文切換帶來的額外開銷,同時使用NIO多路複用機制(單線程維護多個I/O socket的狀態,socket event handler統一進行event分發,並通知到各個event listener),因此即便是單臺Redis server的性能也是很是的快,可支持11萬次/秒的SET操做,8.1萬次/秒的GET操做。算法

高併發系統裏有時候單臺Redis server不能知足性能需求,Redis 3.0以前的辦法是Redis Sentinel,多個節點同時提供服務,而且每一個節點都保存全量數據,Redis 3.0以後引入了Redis Cluster,經過數據分片(Data Sharding)在每一個節點上只保留部分數據(總共有16384個slot)來實現高可用。數據庫

Redis Cluster採用無中心節點方式實現,客戶端直接與redis集羣的每一個節點鏈接,客戶請求到達節點以後,使用統一的哈希算法,CRC16(key)%16384,計算出key對應的slot,而後從Redis Cluster定位出具體的server,具體的data sharding,最終將數據返回給用戶 。但因爲Redis的事務僅能解決單臺server上的ACID問題,對於多臺server常見的問題是多個請求針對同一個key的操做一致性問題,須要結合Zookeeper使用分佈式鎖的機制解決一致性問題和順序操做問題。緩存

Redis支持動態添加和刪除節點,動態遷移和再平衡slot,動態從新選舉Leader並進行fail-over;每個節點雖然只保存一部分的slot,但會保存一份相同的data sharding mapping table,這張表記錄全部16384個slot的host分佈位置,而且節點之間會按期同步更新這張表的信息,這樣的設計能夠保證Redis cluster內部節點之間只須要不多的信息就能夠相互同步信息。客戶端訪問Redis Cluster的時候會指定集羣內的一臺host:port,若是操做的key不在當前的host上,則host會根據data sharding mapping table告訴客戶端正確的host:port;若是訪問的host:port下線了,則客戶端的連接自動轉移到對應的master或者slave節點。cookie

 

Redis中各類數據類型的使用場景
Redis的數據存儲主要經過key/value實現,key都是string類型,value則分不一樣的應用場景有五種類型定義:
#1 string類型:能夠包含任何數據(jps圖片或者通過序列化的對象,單個key最大能夠存儲512M的數據),具備全局統計功能的數據,如全局ID生成器、集羣配置信息等;
#2 hash類型:用於存儲對象結構的數據,多個field綁定到一個key上(對比使用string類型存儲對象的優點在於hash類型能夠直接update具體field的值而不影響其餘field),如實現SSO,cookie爲key,用戶信息爲value,並有指定過時時間;
#3 list類型:用於存儲須要基於隊列或者棧操做的系列數據,如消息隊列;
#4 set類型:用於存儲須要維護一個全局不重複的集合,如服務註冊發現,能夠實現全局去重的功能,如訪問網頁的獨立IP,共同好友等;
#5 zset類型:用於存儲須要維護一個全局不重複但有權重排序的列表可使用SORTED SET,如積分排行榜、帶權重的消息隊列。併發

對上述的字段類型均可以進行的相似的操做,
設置一個值:[set|hmset|lpush|sadd] key value
獲取一個值:[get|hget] key
刪除一個值:[del|hdel] key
設置一個具備過時時間的值:[setex] key time value
若是值不存在就設置這個值:[setnx] key value
查找redis中的keys或者pattern:[keys/scan] key
判斷一個值是否存在:[exists|hexists] key
給指定值設置過時時間:[expire] key seconds
將指定key的value加1|減1:[incr|decr] key
將一個key\value遷移到指定server:[migrate] host port key dest-db timeout [copy] [replace]app

HyperLogLog用於作基數統計(基於set類型的封裝,僅根據輸入的獨立元素個數進行統計,而不存儲元素自己),能夠保證在輸入元素數量或者體積很是大的時候能夠保證統計所需的空間固定爲12kb(最大2^64個元素) 。
在指定的key中添加基數:[pfadd] key value
統計指定key中不一樣基數的個數:[pfcount] key
將sourceKey的技術合併到destKey的基數統計中:[pfmerge] destKey sourceKeydom

Pub/Sub用於作消息的發佈訂閱(基於list類型的封裝,將消息封裝成list的節點)。
建立一個信息接收channel:[subscribe] channel
向指定的channel發送一個信息:[publish] channel messagesocket

單個redis命令的執行具備原子性,對於多個命令而言redis提供基礎事務機制,可是不保證多個命令執行的原子性,一個典型的redis事務以下:
開啓一個事務:[multi]
以後能夠計劃多條redis命令,但並不會執行
提交併執行以前的全部命令:[exec]
開始執行以前計劃的redis命令,若是其中某條命令執行失敗並不會影響其餘命令的執行
取消執行事務塊內全部計劃的redis命令:[discard]
監視一個或者多個key:[watch] key
表示在執行exec以前若是key被事務以前的命令修改,則當前事務被discard。分佈式

 

Redis數據過時策略和內存回收策略
針對已通過期的數據Redis採用按期刪除和延遲刪除結合的策略,可是二者都有缺陷;因爲按期檢查全部的key是否過時會帶來性能問題,所以按期刪除策略使用的是隨機抽查,另外在操做Key前會判斷是否已通過期,如過時則當即刪除;這樣的策略會致使一些已通過期的key還堆積在內存裏,使得redis server內存佔用率居高不下,所以須要結合redis.conf中的maxmemory-policy配置使用,也就是當redis server的內存不足以寫入新數據時的內存回收策略,
#1 noeviction:表示直接報錯;
#2 allkeys-lur:表示在全部keys中根據LRU刪除key;
#3 allkeys-random:表示在全部keys中隨機刪除key;
#4 volatile-lru/volatile-random/volatile-ttl用於當redis server既充當cache又當DB的時候,表示在設置了expire date的keys中進行刪除,ttl表示刪除擁有更早過時時間的key。

 

解決Redis緩存穿透和緩存雪崩問題緩存穿透和雪崩能夠看作一個問題,只是嚴重程度不一樣;當一個請求到達redis以後發現沒有對應的緩存數據,而後向DB發送數據請求,若是能獲取到數據那問題就停留在了緩存穿透上,DB獲取到的數據會緩存到redis上;若是DB中也沒有對應的數據,而且當這樣的請求達到必定數量級而且耗用完全部的DB資源,最終致使DB鏈接異常就出現了緩存雪崩問題。解決緩存穿透問題的思路有下述幾種,不論是否從DB中查找到對應的值(沒有值就爲null),都在redis中記錄一條緩存記錄;在Dao層維護一張BitMap,用bit記錄對應的key是否有對應值,從而避免冗餘的DB操做;後臺線程專門用於更新即將過時的Redis數據,從而避免緩存穿透。解決緩存雪崩問題的思路有下述幾種,在DB Connection上添加互斥鎖,這樣當大量緩存請求失效的時候須要排隊去DB請求數據;對設置了相同過時時間的數據設置一個隨機值,避免數據集體失效;使用雙緩存或者多層緩存策略,須要配合緩存預熱。

相關文章
相關標籤/搜索