1、 Redis官方推薦集羣方案:Redis Clusterhtml
注:適用於redis3.0之後版本(官方集羣版本);node
redis cluster 是redis官方提供的分佈式解決方案,在3.0版本後推出的,有效地解決了redis分佈式的需求,當一個redis節點掛了能夠快速的切換到另外一個節點。
簡介:
1)設計上使用了去中心化,去中間件,集羣中的每一個節點都是平等的關係,都是對等的,每一個節點都保存各自的數據和整個集羣的狀態。每一個節點都和其餘全部節點鏈接,並且這些鏈接保持活躍,這樣就保證了咱們只須要鏈接集羣中的任意一個節點,就能夠獲取到其餘節點的數據。
2)哈希槽設計,使用哈希槽 (hash slot)
的方式來分配數據,redis cluster 默認分配了 16384 個slot每set一個key 時,會用CRC16
算法來取模獲得所屬的slot
,而後將這個key 分到哈希槽區間的節點上,即:CRC16(key) % 16384
。
- 優勢:取中心化,無中心節點;數據按照 slot 存儲分佈在多個 Redis 實例上;平滑的進行擴容/縮容節點;自動故障轉移(節點之間經過 Gossip 協議交換狀態信息,進行投票機制完成 Slave 到 Master 角色的提高),提升了系統的可擴展性和高可用性。
- 缺點:嚴重依賴外部 Redis-Trib,缺少監控管理;須要依賴 Smart Client(鏈接維護, 緩存路由表, MultiOp 和 Pipeline 支持);Failover 節點的檢測過慢,不如「中心節點 ZooKeeper」及時;Gossip 消息的開銷;沒法根據統計區分冷熱數據;Slave「冷備」,不能緩解讀壓力。
架構細節:
(1)全部的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬;
(2)節點的fail是經過集羣中超過半數的節點檢測失效時才生效;
(3)客戶端與redis節點直連,不須要中間proxy層.客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可,
(4)redis-cluster把全部的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value.
redis-cluster選舉(容錯)機制:
(1) leader選舉過程是,集羣中全部master參與,若半數以上master節點與master節點通訊超時(cluster-node-timeout),則認爲當前master節點掛掉.
(2)整個集羣不可用(cluster_state:fail)的條件(集羣不可用時,全部對集羣的操做作都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤),
a:集羣中任意master掛掉,且當前master沒有slave,集羣進入fail狀態;
b:集羣中超過半數以上master掛掉,不管是否有slave,集羣進入fail狀態。
相關原理分析:
分佈式基礎---Redis集羣數據分片
· Redis Cluster沒有使用一致性散列,而是使用不一樣形式的分片slot,其中每一個鍵稱之爲 hash slot.。redis
Redis集羣中有16384個散列槽,爲了計算給定密鑰的散列槽,採用密鑰模數16384的CRC16。算法
Redis羣集中的每一個節點都負責哈希槽的子集,例如,擁有一個包含3個節點的集羣,則:數據庫
- 節點A包含從0到5500的散列槽。
- 節點B包含從5501到11000的散列槽。
- 節點C包含從11001到16383的散列槽。
(1)此特色可輕鬆添加和刪除集羣中的節點。例如,要添加一個新節點D,則將一些哈希槽從節點A,B,C移動到D便可。一樣,若是想從集羣中刪除節點A,只需移動A服務的哈希槽到B和C。當節點A爲空時,就能夠徹底從集羣中刪除它。緩存
(2)由於將哈希槽添加和刪除節點、從一個節點移動到另外一個節點、或者更改節點所持有的哈希槽的百分比,不須要中止操做,因此不須要任何停機時間。服務器
(3)只要涉及單個命令執行(整個事務或Lua腳本執行)的全部鍵都屬於同一個哈希槽,Redis Cluster就支持多個鍵操做。可利用此分片的特色在集羣操做中進行pipline和keys等相關操做。網絡
高可用基礎---Redis Cluster主備模型
爲在主節點子集發生故障或沒法與大多數節點通訊時保持可用,Redis Cluster使用主從模型,其中每一個散列槽從1(主機自己)到N個副本(N) -1個額外的從節點)。建立集羣時,每一個主節點添加一個從節點,以便最終集羣由做爲主節點的A,B,C 和做爲從節點的A1,B1,C1組成。若是節點B出現故障,系統就能繼續運行。節點B1複製B,B失敗,集羣將節點B1升級爲新的主節點,並將繼續正常運行。架構
注意,若是節點B和B1同時發生故障,Redis Cluster將沒法繼續運行。併發
備註:非主從模式,Redis Cluster集羣方案採用的是去中心化的方式,全部節點皆爲主節點Master,從節點指的是備份節點,保證高可用。若其一物理節點主節點掛掉的狀況下,會啓動從節點提供服務,若主從同時關掉,則集羣再也不提供服務。
Redis集羣一致性保證
Redis Cluster沒法保證強一致性。在某些條件下,Redis Cluster可能會丟失系統向客戶端確認的寫入。
Redis Cluster可能丟失寫入的第一個緣由是它使用異步複製。即在寫入期間會發生如下狀況:
- 客戶端寫入master B.
- master B向客戶端回覆肯定。
- master B將寫入傳播到其從設備B1,B2和B3。
(1)B在回覆客戶端以前並無等待來自B1,B2,B3的確認,由於這對Redis來講是一個太高的延遲,因此若是客戶端寫了一些東西,B會確認寫入,可是在崩潰以前可以將寫入發送到其slave,其中一個slave(沒有接收到寫入)被提高爲master ,永遠丟失寫入。
這和大多數數據庫配置爲每秒將數據刷新到磁盤的所發生的狀況很是類似。一樣,能夠經過在回覆客戶端以前強制數據庫刷新磁盤上的數據來提升一致性,但會致使性能太低。在Redis Cluster中,至關於使用同步複製。
解決辦法,須要在性能和一致性之間進行權衡。
Redis Cluster在絕對須要時支持同步寫入,經過WAIT命令實現,使得丟失寫入的可能性大大下降,但即便使用同步複製,Redis Cluster也不會實現強一致性:在更復雜的狀況下老是能夠實現失敗場景,沒法接收寫入的slave被選爲master。
(2)還有另外一個值得注意的狀況是,網絡分區中,其中客戶端與少數實例(至少包括主服務器)隔離,Redis集羣會丟失寫入數據。如,
以6個節點簇爲例,包括A,B,C,A1,B1,C1,3個主站和3個從站。還有一個client,咱們稱之爲Z1。
在發生分區以後,可能在分區的一側有A,C,A1,B1,C1,在另外一側有B和Z1。
Z1仍然能夠寫入B,它將接受其寫入。若是分區在很短的時間內恢復,集羣將繼續正常運行。可是,若是分區持續足夠的時間使B1在分區的多數側被提高爲主,則Z1發送給B的寫入將丟失。
注意,Z1將可以發送到B的寫入量存在maximum window:若是分區的多數方面已經有足夠的時間將slave選爲master,則少數端的每一個主節點都會中止接受寫入。
這段時間是Redis Cluster的一個很是重要的配置指令,稱爲節點超時。
節點超時事後,master被視爲失敗,能夠由其中一個副本替換。相似地,在節點超時已通過去而主節點沒法感知大多數其餘主節點以後,它進入錯誤狀態並中止接受寫入。
2、擴展:
Redis3.0以前的使用集羣方案相關概念:
(1)哨兵(Sentinel )機制
Sentinel(哨兵)是Redis 的高可用性解決方案:由一個或多個Sentinel 實例 組成的Sentinel 系統能夠監視任意多個主服務器,以及這些主服務器屬下的全部從服務器,並在被監視的主服務器進入下線狀態時,自動將下線主服務器屬下的某個從服務器升級爲新的主服務器。
Redis哨兵機制運行流程:
1):每一個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其餘 Sentinel 實例發送一個 PING 命令
2):若是一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel 標記爲主觀下線。
3):若是一個Master被標記爲主觀下線,則正在監視這個Master的全部 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態。
4):當有足夠數量的 Sentinel(大於等於配置文件指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態, 則Master會被標記爲客觀下線
5):在通常狀況下, 每一個 Sentinel 會以每 10 秒一次的頻率向它已知的全部Master,Slave發送 INFO 命令
6):當Master被 Sentinel 標記爲客觀下線時,Sentinel 向下線的 Master 的全部 Slave 發送 INFO 命令的頻率會從 10 秒一次改成每秒一次
7):若沒有足夠數量的 Sentinel 贊成 Master 已經下線, Master 的客觀下線狀態就會被移除。
若 Master 從新向 Sentinel 的 PING 命令返回有效回覆, Master 的主觀下線狀態就會被移除。
(2)Redis主從讀寫分離
1)主從複製:主節點負責寫數據,從節點負責讀數據,主節點按期把數據同步到從節點保證數據的一致性。
2)負載均衡:當Master宕機後,經過選舉算法從slave中選舉出新Master繼續對外提供服務,主機恢復後以slave的身份從新加入,從節點經過負載均衡提供取服務。
備註:主從複製和哨兵機制須要進行手動配置,使用zookeeper做爲監控中心;3.0之後的版本去中心化,再也不須要zookeeper提供監控服務。
3、Redis做爲緩存應用問題及解決方案:
1)緩存穿透
緩存穿透是指查詢一個必定不存在的數據,因爲緩存是不命中時須要從數據庫查詢,查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到數據庫去查詢,形成緩存穿透。
解決辦法:
-
對全部可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則丟棄。還有最多見的則是採用布隆過濾器,將全部可能存在的數據哈希到一個足夠大的bitmap中,一個必定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。
-
也能夠採用一個更爲簡單粗暴的方法,若是一個查詢返回的數據爲空(無論是數據不存在,仍是系統故障),咱們仍然把這個空結果進行緩存,但它的過時時間會很短,最長不超過五分鐘。
2)緩存雪崩
若是緩存集中在一段時間內失效,發生大量的緩存穿透,全部的查詢都落在數據庫上,形成了緩存雪崩。
解決辦法:
-
在緩存失效後,經過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。好比對某個key只容許一個線程查詢數據和寫緩存,其餘線程等待。
-
能夠經過緩存reload機制,預先去更新緩存,再即將發生大併發訪問前手動觸發加載緩存
-
不一樣的key,設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻. 好比咱們能夠在原有的失效時間基礎上增長一個隨機值,好比1-5分鐘隨機,這樣每個緩存的過時時間的重複率就會下降,就很難引起集體失效的事件
-
作二級緩存,或者雙緩存策略。A1爲原始緩存,A2爲拷貝緩存,A1失效時,能夠訪問A2,A1緩存失效時間設置爲短時間,A2設置爲長期。
3)緩存擊穿
緩存被「擊穿」的問題,這個和緩存雪崩的區別在於這裏針對某一key緩存,前者則是不少key。
4)緩存預熱
緩存預熱就是系統上線後,提早將相關的緩存數據直接加載到緩存系統。避免在用戶請求的時候,先查詢數據庫,而後再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數據!
緩存預熱解決方案:
-
直接寫個緩存刷新頁面,上線時手工操做下;
-
數據量不大,能夠在項目啓動的時候自動進行加載;
-
定時刷新緩存;
5)緩存更新
咱們知道經過expire來設置key 的過時時間,那麼對過時的數據怎麼處理呢?除了緩存服務器自帶的緩存失效策略以外(Redis默認的有6中策略可供選擇),咱們還能夠根據具體的業務需求進行自定義的緩存淘汰,常見的策略有兩種:
-
定時去清理過時的緩存;
-
當有用戶請求過來時,再判斷這個請求所用到的緩存是否過時,過時的話就去底層系統獲得新數據並更新緩存。
二者各有優劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較複雜!具體用哪一種方案,你們能夠根據本身的應用場景來權衡。
6)緩存降級
當訪問量劇增、服務出現問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然須要保證服務仍是可用的,即便是有損服務。系統能夠根據一些關鍵數據進行自動降級,也能夠配置開關實現人工降級。 降級的最終目的是保證核心服務可用,即便是有損的。並且有些服務是沒法降級的(如加入購物車、結算)。 在進行降級以前要對系統進行梳理,看看系統是否是能夠丟卒保帥;從而梳理出哪些必須誓死保護,哪些可降級;好比能夠參考日誌級別設置預案:
-
通常:好比有些服務偶爾由於網絡抖動或者服務正在上線而超時,能夠自動降級;
-
警告:有些服務在一段時間內成功率有波動(如在95~100%之間),能夠自動降級或人工降級,併發送告警;
-
錯誤:好比可用率低於90%,或者數據庫鏈接池被打爆了,或者訪問量忽然猛增到系統能承受的最大閥值,此時能夠根據狀況自動降級或者人工降級;
-
嚴重錯誤:好比由於特殊緣由數據錯誤了,此時須要緊急人工降級。
4、redis做爲分佈式鎖方案(性能最優)
分佈式鎖是控制分佈式系統之間同步訪問共享資源的一種方式。
實現思路:
- 使用
SETNX
命令獲取鎖,若不存在則設置值,設置成功則表示取得鎖成功;
- 設置expire,保證超時後能自動釋放鎖(使用lua腳本將setnx和expire變成一個原子操做);
- 釋放鎖,使用
DEL
命令將鎖數據刪除。
或使用Redis官方推薦的redission
另偶爾看到一位同胞使用圖文的形式直觀展現了原理部分,現附上連接,共同進步:https://www.jianshu.com/p/6e2a50b0f835