若是你用redis緩存技術的話,確定要考慮如何用redis來加多臺機器,保證redis是高併發的,還有就是如何讓Redis保證本身不是掛掉之後就直接死掉了,redis高可用node
redis高併發:主從架構,一主多從,通常來講,不少項目其實就足夠了,單主用來寫入數據,單機幾萬QPS,多從用來查詢數據,多個從實例能夠提供每秒10萬的QPS。redis
redis高併發的同時,還須要容納大量的數據:一主多從,每一個實例都容納了完整的數據,好比redis主就10G的內存量,其實你就最對只能容納10g的數據量。若是你的緩存要容納的數據量很大,達到了幾十g,甚至幾百g,或者是幾t,那你就須要redis集羣,並且用redis集羣以後,能夠提供可能每秒幾十萬的讀寫併發。算法
redis高可用:若是你作主從架構部署,其實就是加上哨兵就能夠了,就能夠實現,任何一個實例宕機,自動會進行主備切換。 下面詳細介紹數據庫
redis要搞高併發,那就要把底層的緩存搞好,讓更少的請求直接到數據庫,由於數據庫的高併發實現起來是比較麻煩的,並且有些操做還有事務的要求等等,因此很難作到很是高的併發。
redis併發作的好對於整個系統的併發來講仍是不夠的,可是redis做爲整個大型的緩存架構,在支撐高併發的架構裏面是很是重要的一環。
要實現系統的高併發,首先緩存中間件、緩存系統必需要可以支撐起高併發,而後在通過良好的總體緩存架構設計(多級緩存、熱點緩存),才能真正支撐起高併發。緩存
redis不能支撐高併發的瓶頸主要是單機問題,也就是說只有一個單一的redis,就算機器性能再怎麼好,也是有上限的。安全
單機的redis不可能支撐過高的併發量,要想支持更高的併發能夠進行 讀寫分離 。對於緩存來講,通常都是支撐讀高併發的,寫的請求是比較少的,所以能夠基於主從架構進行讀寫分離。網絡
配置一個master(主)機器用來寫入數據,配置多個slave(從)來進行數據的讀取,在master接收到數據以後將數據同步到slave上面便可,這樣slave能夠配置多臺機器,就能夠提升總體的併發量。架構
一個master節點下面掛若干個slave節點,寫操做將數據寫到master節點上面去,而後在master寫完以後,經過異步操做的方式將數據同步到全部的slave節點上面去,保證全部節點的數據是一致的。併發
(1)redis採用異步方式複製數據到slave節點,不過redis2.8開始,slave node會週期性地確認本身每次複製的數量。
(2)一個master node 能夠配置多個 salve node。
(3)slave node也能夠鏈接其餘的slave node。
(4)slave node作複製分時候,是不會阻塞master node的正常工做的。
(5)slave node在作複製的時候,也不會阻塞本身的操做,它會用舊的數據來提供服務;可是複製完成的時候,須要刪除舊的數據,加載新的數據,這個時候會對外暫停提供服務。
(6)slave node主要用來進行橫向擴容,作讀寫分離,擴容的slave node 能夠提升吞吐量。less
若是採用這種主從架構,那麼必需要開啓master node的持久化。不建議使用slave node做爲master node的熱備份,由於若是這樣的話,若是master一旦宕機,那麼master的數據就會丟失,重啓以後數據是空的,其餘的slave node要是來複制數據的話,就會複製到空,這樣全部節點的數據就都丟了。
要對備份文件作多種冷備份,防止整個機器壞了,備份的rdb數據也丟失的狀況。
①當啓動一個slave node的時候,它會發送一個PSYNC 命令給master node。
②若是這個slave node是從新鏈接master node,那麼master node 僅僅會複製給slave部分缺失的數據;若是是第一次鏈接master node,那麼就會觸發一次 full resynchronization。
③開始 full resynchronization的時候,master會啓動一個後臺線程 ,開始生成一份RDB快照文件,同時還會將從客戶端新接收到的全部寫命令緩存在內存當中。
④master node將生成的RDB文件發送給slave node,slave現將其寫入本地磁盤,而後再從磁盤加載到內存當中。而後master node會將內存中緩存的寫命令發送給slave node,slave node也會同步這部分數據 。
⑤slave node若是跟master node由於網絡故障斷開了鏈接,會自動重連 。
⑥master若是發現有多個slave node來從新鏈接,僅僅會啓動一個rdb save操做 ,用一份數據服務全部slave node。
從redis2.8開始支持斷點續傳。若是在主從複製的過程當中,網絡忽然斷掉了,那麼能夠接着上次 複製的地方,繼續複製,而不是從頭複製一份。
原理: master node會在內存中建立一個backlog,master和slave都會保存一個replica offset還有一個master id,offset就保存在backlog中。若是master和slave網絡鏈接斷掉了,slave會讓master從上次的replica offset開始繼續複製。可是若是沒有找到offset,就會執行一次 full resynchronization操做。
無磁盤化複製是指,master直接再內存中建立RDB文件,而後發送給slave,不會在本身本地磁盤保存數據。 設置方式
配置 repl-diskless-sync和repl-diskless-sync-delay參數。
repl-diskless-sync:該參數保證進行無磁盤化複製。
repl-diskless-sync-delay:該參數表示等待必定時長再開始複製,這樣能夠等待多個slave節點重新鏈接上來。
slave不會過時key ,只有等待master過時key。
若是master過時了一個key,或者淘汰了一個key,那麼master會模擬發送一條del命令 給slave,slave接到以後會刪除該key。
①slave node啓動,僅僅保存了master node的信息,包括master node的host和ip,可是數據複製尚未開始。 master node的host和ip是在redis.conf文件裏面的slaveOf中配置的 。
②slave node內部有一個定時任務,每秒檢查是否有新的master node要鏈接個複製,若是發現,就跟master node創建socket網絡鏈接。
③slave node發送ping命令給master node。
④若是master設置了requirepass,那麼slave node必須發送master auth的口令過去進行口令驗證。
⑤master node第一次執行全量複製,將全部數據發送給slave node。
⑥master node持續降寫命令,異步複製給slave node。
指的是slave第一次鏈接master時的狀況,執行的是全量複製。
①master和slave都會維護一個offset
master會在自身不斷累加offset,slave也會在自身不斷累加offset。slave每秒都會上報本身的offset給master,同時master也會保存每一個slave的offset。
這個倒不是說特定就用在全量複製的,主要是master和slave都要知道各自的數據的offset,才能知道互相之間的數據不一致的狀況
②backlog
master node有一個backlog在內存中,默認是1M大。
master node給slave node複製數據時,也會將數據在backlog中同步一份。
backlog主要是用來作全量複製中斷時候的增量複製的。
③master run id
redis經過info server 能夠查看到master run id。
用途:slave根據其來定位惟一的master。
爲何不用host+ip : 由於使用host+ip來定位master是不靠譜的,若是master node重啓或者數據出現了變化,那麼slave應該根據不一樣的master run id進行區分,run id不一樣就須要作一次全量複製。
若是須要不更改run id重啓redis,可使用redis-cli debug reload 命令。
①master執行bgsave,在本地生成一份RDB文件。
②master node將RDB快照文件發送給slave node,若是RDB文件的複製時間超過60秒(repl-timeout),那麼slave node就會任務複製失敗,能夠適當調整這個參數。
③對於千兆網卡的機器,通常每秒傳輸100M,傳輸6G文件極可能超過60秒。
④master node在生成RDB文件時,會將全部新接到的寫命令緩存在內存中,在slave node保存了RDB文件以後,再將這些寫命令複製個slave node。
⑤查看client-output-buffer-limit slave 參數,好比[client-output-buffer-limit slave 256MB 64MB 60],表示在複製期間,內存緩存去持續消耗超過64M,或者一次性超過256MB,那麼中止複製,複製失敗。
⑥slave node接收到RDB文件以後,清空本身的數據,而後從新加載RDB文件到本身的內存中,在這個過程當中,基於舊數據對外提供服務。
⑦若是slave node開啓了AOF,那麼會當即執行BRREWRITEAOF,從新AOF
rdb生成、rdb經過網絡拷貝、slave舊數據的清理、slave aof rewrite,很耗費時間
若是複製的數據量在4G~6G之間,那麼極可能全量複製時間消耗到1分半到2分鐘
①若是全量複製過程當中,master和slave網絡鏈接斷掉,那麼slave從新鏈接master會觸發增刊複製。
②master直接從本身的backlog中獲取部分丟失是數據,發送給slave node。
③master就是根據slave發送的psync中的offset來從backlog中獲取數據的。
master和slave互相都會發送heartbeat信息。
master默認每隔10秒發送一次,slave node默認每隔1秒發送一次。
master每次接收到寫命令以後,如今內部寫入數據,而後異步發送給slave node
高可用性(英語:high availability,縮寫爲 HA),IT術語,指系統無中斷地執行其功能的能力,表明系統的可用性程度。是進行系統設計時的準則之一。高可用性系統與構成該系統的各個組件相比能夠更長時間運行。 高可用性一般經過提升系統的容錯能力來實現。定義一個系統怎樣纔算具備高可用性每每須要根據每個案例的具體狀況來具體分析。 其度量方式,是根據系統損害、沒法使用的時間,以及由沒法運做恢復到可運做情況的時間,與系統總運做時間的比較。計算公式爲:
A(可用性),MTBF(平均故障間隔),MDT(平均修復時間) 在線系統和執行關鍵任務的系統一般要求其可用性要達到5個9標準(99.999%)。 ![]()
可用性 | 年故障時間 |
---|---|
99.9999% | 32秒 |
99.999% | 5分15秒 |
99.99% | 52分34秒 |
99.9% | 8小時46分 |
99% | 3天15小時36分 |
redis不能夠包含了單實例的不可用,主從架構的不可用。
不可用的狀況:
①主從架構的master節點掛了,若是master節點掛了那麼緩存數據沒法再寫入,並且slave裏面的數據也沒法過時,這樣就致使了不可用。
②若是是單實例,那麼可能由於其餘緣由致使redis進程死了。或者部署redis的機器壞了。
不可用的後果 :首先緩存不可用了,那麼請求就會直接走數據庫,若是涌入大量請求超過了數據庫的承載能力,那麼數據庫就掛掉了,這時候若是不能及時處理好緩存問題,那麼因爲請求過多,數據庫重啓以後很快就又會掛掉,直接致使整個系統不可用。
①保證每一個redis都有備份。
②保證在當前redis出故障以後,能夠很快切換到備份redis上面去。
爲了解決這個問題,引入下面的哨兵機制。
哨兵(Sentinal)是redis集羣架構當中很是重要的一個組件,它主要有一下功能:
①集羣監控 ,負責監控redis master和slave進程是否正常工做。
②消息通知 ,若是某個redis實例有故障,那麼哨兵負責發送消息做爲報警通知給管理員。
③故障轉移 ,若是master掛掉了,會自動轉移到slave上。
④配置中心 ,若是故障發生了,通知client客戶端鏈接到新的master上面去。
①哨兵自己是分佈式的,須要做爲一個集羣去運行,個哨兵協同工做。
②故障轉移時,判斷一個master宕機了,須要大部分哨兵贊成才行。
③即便部分哨兵掛掉了,哨兵集羣仍是能正常工做的。
④哨兵至少須要3個實例,來保證本身的健壯性。
⑤哨兵+redis主從結構,是沒法保證數據零丟失的,只會保證redis集羣的高可用。
⑥對應哨兵+redis主從這種架構,再使用以前,要作重複的測試和演練。
哨兵集羣必須部署2個以上的節點。若是集羣僅僅部署了2個哨兵實例,那麼quorum=1(執行故障轉移須要贊成的哨兵個數)。
Configuration: quorum = 2,majority=2
若是M1所在機器宕機了,那麼三個哨兵還剩下2個,S2和S3能夠一致認爲master宕機,而後選舉出一個來執行故障轉移
同時3個哨兵的majority是2,因此還剩下的2個哨兵運行着,就能夠容許執行故障轉移
①異步複製致使的數據丟失
由於從master到slave的數據複製過程是異步的,可能有部分數據還沒來得及複製到slave上面去,這時候master就宕機了,那麼這部分數據就丟失了。
②集羣腦裂致使的數據丟失
什麼是腦裂:腦裂,也就是說,某個master所在機器忽然脫離了正常的網絡,跟其餘slave機器不能鏈接,可是實際上master還運行着。
此時哨兵可能就會認爲master宕機了,而後開啓選舉,將其餘slave切換成了master。
這個時候,集羣裏就會有兩個master,也就是所謂的腦裂。
此時雖然某個slave被切換成了master,可是可能client還沒來得及切換到新的master,還繼續寫向舊master的數據可能也丟失了。
所以舊master再次恢復的時候,會被做爲一個slave掛到新的master上去,本身的數據會清空,從新重新的master複製數據
要解決這個問題,就須要配置兩個參數:
min-slaves-to-write 1 和 min-slaves-max-lag :
表示 要求至少有一個slave 在進行數據的複製和同步的延遲不能超過10秒。
若是一旦全部的slave數據同步和複製的延遲都超過了10秒,那麼這個時候,master就會在接受任何請求了。
①減小異步複製的數據丟失
有了min-slaves-max-lag這個配置,就能夠確保說,一旦slave複製數據和ack延時太長,就認爲可能master宕機後損失的數據太多了,那麼就拒絕寫請求,這樣能夠把master宕機時因爲部分數據未同步到slave致使的數據丟失下降的可控範圍內。
(2)減小腦裂的數據丟失 若是一個master出現了腦裂,跟其餘slave丟了鏈接,那麼上面兩個配置能夠確保說,若是不能繼續給指定數量的slave發送數據,並且slave超過10秒沒有給本身ack消息,那麼就直接拒絕客戶端的寫請求。 這樣腦裂後的舊master就不會接受client的新數據,也就避免了數據丟失。
上面的配置就確保了,若是跟任何一個slave丟了鏈接,在10秒後發現沒有slave給本身ack,那麼就拒絕新的寫請求。 所以在腦裂場景下,最多就丟失10秒的數據
sdown是主觀宕機,就一個哨兵若是本身以爲一個master宕機了,那麼就是主觀宕機
odown是客觀宕機,若是quorum數量的哨兵都以爲一個master宕機了,那麼就是客觀宕機
sdown達成的條件很簡單,若是一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數以後,就主觀認爲master宕機
sdown到odown轉換的條件很簡單,若是一個哨兵在指定時間內,收到了quorum指定數量的其餘哨兵也認爲那個master是sdown了,那麼就認爲是odown了,客觀認爲master宕機。
①哨兵相互之間的發現,是經過redis的pub/sub系統實現的,每一個哨兵都會往 __sentinel__:hello 這個channel裏面發送一個消息,這時候其餘的哨兵均可以消費這個消息,並感知其餘哨兵的存在。
②每一個兩秒鐘,每一個哨兵都會往本身監控的某個master+slave對應的 __sentinel__:hello channel裏面發送一個消息,內容是本身的host、ip和run id還有對這個master的監控配置。
③每一個哨兵也會去監聽本身監控的每一個master+slave對應的 __sentinel__:hello channel,r而後去感知到一樣在監聽這個master+slave的其餘哨兵的存在。
④每一個哨兵還會根據其餘哨兵交換對master的監控配置,互相進行監控配置的同步。
哨兵會負責自動糾正slave的一些配置,好比slave若是要成爲潛在的master候選人,哨兵會確保slave在複製現有master數據;若是slave鏈接到了一個錯誤的master上,好比故障轉移以後,那麼哨兵會確保他們鏈接到正確的master上來。
若是一個master被認爲odown了,並且majority數量的哨兵都容許了主備切換,那麼某個哨兵就會執行主備切換,此時首先要選舉一個slave出來。選舉會考慮到一下狀況:
①slave跟master斷開鏈接的時長
②slave的優先級
③slave複製數據的offset
④slave的run id
首先,若是一個slave跟master斷開鏈接已經超過了 down-after-millisecondes 的10倍,外加master宕機的時長,那麼slave就被認爲不適合選舉爲master了。
即:斷開鏈接時間 > (down-after-milliseconds * 10 + milliseconds_since_master_is_in_SDOWN_state).
對應剩下的slave按照以下規定排序:
①首先,按照slave的優先級進行排序,slave priority越低,優先級就越高。
②若是優先級相同,那麼就看replica offset,那個slave複製了越多的數據,offset越靠後,優先級就越高。
③若是上面都想同,那就選擇run id最小的那個slave。
每次一個哨兵作主備切換,首先須要quorum數量的哨兵認爲odown,而後選舉出一個哨兵來作主備切換,這個哨兵還要獲得majority數量哨兵的受權,才能正式執行切換。
若是quorum < majority ,好比5個哨兵,majority就是3(超過半數),quorum設置爲2,那麼就須要3個哨兵受權就能夠執行切換。
若是 quorum >= majority,那麼必須quorum數量的哨兵都受權才能夠進行切換,好比5個哨兵,quorum是5,那麼必須5個哨兵都贊成受權,才能夠進行切換。
哨兵會對一套redis master+slave進行監控,有相應的監控的配置。
執行切換的那個哨兵,會從要切換到的新master(salve->master)那裏獲得一個configuration epoch,這就是一個version號,每次切換的version號都必須是惟一的。
若是第一個選舉出的哨兵切換失敗了,那麼其餘哨兵,會等待failover-timeout時間,而後接替繼續執行切換,此時會從新獲取一個新的configuration epoch,做爲新的version號。
七、configuraiton傳播
哨兵完成切換以後,會在本身本地更新生成最新的master配置,而後同步給其餘的哨兵,就是經過以前說的pub/sub消息機制。
這裏以前的version號就很重要了,由於各類消息都是經過一個channel去發佈和監聽的,因此一個哨兵完成一次新的切換以後,新的master配置是跟着新的version號的。
其餘的哨兵都是根據版本號的大小來更新本身的master配置的。