昨天回顧到redis的過時策略今天繼續node
要搞清這個問題能夠從這個四個方面來弄mysql
一、首先要知道redis高併發跟整個系統的高併發之間的關係redis
要作高併發的話,不可避免的要把底層的緩存搞得很OK
其實mysql也能夠高併發,經過一系列複雜的分庫分表,訂單系統,
事務要求的,QPS到幾萬,比較高了。要是作一些電商得商品詳情頁
,真正得超高併發(雖然我沒經歷過,可是也要見識下,作好準備)其實一秒鐘幾百萬,光redis也是不夠得,可是redis是整個大型得緩存架構中支撐高併發得重要環節。
複製代碼
二、redis不能支撐高併發是由於什麼?算法
哈哈就是由於單機啊,俗話說雙拳難敵四手
複製代碼
三、假如redis要是支撐超過10萬+得併發,應該怎麼搞sql
除去特殊狀況,能夠作一個主從架構得讀寫分離,先假設寫得操做少大部分是讀操做
看圖
複製代碼
怎麼實現呢能夠了解下 redis得replication 主從複製功能
複製代碼
上邊說到了 redis replication這個東西緩存
借用一下圖,比較清楚,最基本得就是複製安全
(1)redis採用異步方式複製數據到slave節點,不過redis 2.8開始,slave node會週期性地確認本身每次複製的數據量
(2)一個master node是能夠配置多個slave node的
(3)slave node也能夠鏈接其餘的slave node
(4)slave node作複製的時候,是不會block master node的正常工做的
(5)slave node在作複製的時候,也不會block對本身的查詢操做,它會用舊的數據集來提供服務; 可是複製完成的時候,須要刪除舊數據集,加載新數據集,這個時候就會暫停對外服務了
(6)slave node主要用來進行橫向擴容,作讀寫分離,擴容的slave node能夠提升讀的吞吐量
slave,高可用性,有很大的關係
複製代碼
若是採用了主從架構,那麼建議必須開啓master node的持久化!
不建議用slave node做爲master node的數據熱備,由於那樣的話,若是你關掉master的持久化,可能在master宕機重啓的時候數據是空的,而後可能一通過複製,salve node數據也丟了
master -> RDB和AOF都關閉了 -> 所有在內存中
master宕機,重啓,是沒有本地數據能夠恢復的,而後就會直接認爲本身IDE數據是空的
master就會將空的數據集同步到slave上去,全部slave的數據所有清空
100%的數據丟失
master節點,必需要使用持久化機制
第二個,master的各類備份方案,要不要作,萬一說本地的全部文件丟失了; 從備份中挑選一份rdb去恢復master; 這樣才能確保master啓動的時候,是有數據的
複製代碼
可是 這個時候仍是有問題得,好比:網絡
即便採用了後續講解的高可用機制,slave node能夠自動接管master
node,可是也可能sentinal尚未檢測到master failure,master node就自動重啓了,仍是可能致使上面的全部slave node數據清空故障
複製代碼
當啓動一個slave node得時候,他會發送一個PSYNC命令給master node,
若是這是一個slave node 從新鏈接 master node,這個時候master node僅僅會複製給slave部分缺乏得數據,若是是第一次就觸發一次full resynchronization(複製全部)
開始full resynchronization得時候,master會啓動一個後臺線程,開始生成一份RDB快照文件,同時還會將從客戶端收到得全部寫命令緩存在內存中。RDB文件完過後,slave就會收到這個文件,
slave會先把他給保存到本地得磁盤中,而後再從磁盤加載到內存中。
slave node若是跟master node有網絡故障,斷開了鏈接,會自動重連
假如master發現有多個slave都來從新鏈接,那麼那個生成得RDB文件誰來鏈接就給誰一份。
複製代碼
從redis 2.8開始,就支持主從複製得斷點續傳。
master node內存中有一個backlog,master 和 slave都會保存一個replica offset,海有一個master id。
offset就是保存在backlog中得。若是master和slave網絡鏈接斷掉了,slave會讓master從上次得 replica offset開始繼續複製。
固然若是沒有找到,就是從頭再來了
複製代碼
master在內存中直接建立rdb,而後給slave,本身不會保存在本地磁盤中了
因此這個時候 repl-diskless-sync-delay 這個配置就重要了,好不容易生成一個rdb,爲啥很少等會看看slave還有沒有再來鏈接得了
複製代碼
slave 不會過時key(只讀哪有資格過時key)。若是master過時了key,或者經過LRU淘汰了一個key,這個時候就會模擬一條del命令發送給slave。
複製代碼
這節再研究下這個複製怎麼搞定的架構
一、slave node啓動,僅僅保存master node 的信息,包括master
node的host和ip,可是複製流程還沒開始了,
問題來了 master host和ip是從哪裏來的(redis.conf裏面的slaveof配置的)
二、slave node內部有個定時任務,每秒檢查是否有新的master node
要鏈接和複製,若是發現,就跟master node創建socket網鏈接
三、slave node發送ping命令給master node
四、口令認證,若是master設置了requirepass,那麼salve node必須發送masterauth的口令過去
進行認證
五、master node第一次執行全量複製,將全部數據發給slave node
六、master node後續持續 將沒有在rdb內的數據,異步複製給slave node
複製代碼
#####二、數據同步相關的核心機制併發
指的就是第一次slave鏈接msater的時候,執行的全量複製,那個過程裏面你的一些細節的機制
(1)master和slave都會維護一個offset
master會在自身不斷累加offset,slave也會在自身不斷累加offset
slave每秒都會上報本身的offset給master,同時master也會保存每一個slave的offset
這個也不是說就是用在全量複製的,主要master和slave都要知道本身數據的offset,才能互相知道數據不一致的狀態
二、backlog,master node有一個backlog,默認的大小是1MB,master node
給slave node複製數據的時候,也會將數據在backlog中同步寫一份,
backlog主要用來作全量複製時中斷後的增量複製。
三、master run id,info server,能夠看到master run id,爲何要這個呢?
若是根據host+ip定位maser node這樣不靠譜(爲何不靠譜 看下邊圖)。
複製代碼
固然假如你就想重啓一下redis沒有想到要同步數據,也有辦法的可使用redis-cli debug reload命令
四、psync,從節點使用psync從master node 進行復制,psync runid offset
master node會根據自身的狀況返回響應信息,多是FULLRESYNC
runid offset觸發全量複製,多是CONTINUE觸發增量複製
複製代碼
一、master執行bgsave,在本地生成一份rdb快照
二、master node將rdb快照文件發送給salve node,若是rdb複製超過60秒(repl-timeout)這個時候slave node就認爲複製
失敗了,若是你的網速不給力最好仍是調節一下這個參數
三、若是你的機器是千兆網卡,通常一秒傳100MB,6G文件,輕鬆超過60秒.
四、master node 生成rdb的時候,他會將全部新的寫命令存在緩存中(我一邊生
rdb一邊來數據,我豈不是永遠寫不完了),而後salve node保存rdb之後再把新數據發給他
五、client-output-buffer-limit slave 256MB 60MB 60 這個參數意思是:
若是在複製期間,內存緩衝區持續消耗超過64MB,或者一次性超過256MB,那麼中止複製,複製失敗
六、slave node收到rdb之後,會將之前的數據清除掉,而後從新加載rdb(這個時候有客戶來訪怎麼辦,把之前舊數據給他)
七、若是slave node開啓了AOF,這個時候會當即執行BGREWRITEAOF,重寫AOF
這個全量複製總的來講:rdb生成、rdb經過網絡拷貝、slave舊
數據的清理、slave aof rewrite,很耗費時間的,
若是複製在4G-6G之間,極可能要消耗一分半到2分鐘
複製代碼
一、若是全量複製的時候,突然斷掉了,salve從新連接master的時候,就會觸發增量
二、master直接從本身的backlog中獲取部分丟失的數據,發給slave node,默認backlog就是1MB
三、master就是根據slave發送的psync中的offset來從backlog獲取數據的
複製代碼
主從節點都會相互發送heartbeat信息
master默認每隔10秒發送一次heartbeat,slave node每隔一秒發送一個heartbeat
複製代碼
master每次接受寫命令的時候先將數據寫進去,而後異步發給slave node
複製代碼
嗯...高可用就是你的服務能夠整年無休一直提供服務(服務不掛就OK)
問題來了redis怎麼作到高可用呢(悄悄說下可使用哨兵模式,這個名詞是否是很高大上) 下邊開始研究下哨兵吧
sentinal,中文叫哨兵
哨兵呢是redis集羣架構中一個很是重要的組件,主要功能有如下幾點
一、集羣監控,負責監控master 和slave是否在正常工做
二、消息通知,若是某個redis實例有故障了,哨兵負責發送消息通知管理員
三、故障轉移,若是master node掛了,會自動選一個slave node 頂上去
四、配置中心,若是故障轉移發生了,通知各個客戶端新的master地址
複製代碼
固然了哨兵做爲監督的,若是監督的掛了怎麼辦,因此哨兵也須要集羣
一、故障轉移的時候,判斷一個master node是宕機了,須要大部分哨兵贊成才能夠,因此就有了分佈式的
選舉(感受跟一個小國家同樣,要換帶頭人、要選舉)
二、即便一個哨兵不行了,還有別的哨兵能幹活,因此配置個哨兵集羣多重要(總不能點背到幾點,哨兵集體罷工吧)
目前redis採用的是sentinal2版本,是1的升級版。升級的目的就是爲了讓故障轉移更健壯,和簡單
複製代碼
一、哨兵至少須要3個,來保證本身健壯
二、其實呢哨兵+主從架構也不能保證數據零丟失,只能保證redis集羣的高可用
三、用這種複雜架構,多測試吧。若是崩盤就尷尬了
複製代碼
看我辯解
若是哨兵集羣僅僅部署了個2個哨兵實例,quorum=1
+----+ +----+
| M1 |---------| R1 |
| S1 | | S2 |
+----+ +----+
Configuration: quorum = 1
master宕機,s1和s2中只要有1個哨兵認爲master宕機就能夠還行切換,同時s1和s2中會選舉出一個哨兵來執行故障轉移
同時這個時候,須要majority,也就是大多數哨兵都是運行的,
2個哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2個哨兵都運行着,就能夠容許執行故障轉移
可是若是整個M1和S1運行的機器宕機了,那麼哨兵只有1個了,
此時就沒有majority來容許執行故障轉移,雖然另一臺機器還
有一個R1,可是故障轉移不會執行
複製代碼
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
Configuration: quorum = 2,majority
若是M1所在機器宕機了,那麼三個哨兵還剩下2個,S2和S3能夠一致認爲master宕機,而後選舉出一個來執行故障轉移
同時3個哨兵的majority是2,因此還剩下的2個哨兵運行着,就能夠容許執行故障轉移
複製代碼
主備切換的時候,可能會有數據丟失
一、異步複製的時候數據丟失,就是master再給slave異步發數據,忽然master掛掉了,那麼master內的數據就沒了
二、腦裂丟失數據:假如你的網很差master所在的機器網絡不正常了,跟其餘slave不能鏈接了,可是master還在運行。
這個事被哨兵發現了,哨兵從新選了一個master,(這個時候就有兩個master,就是所謂的腦裂)雖然選了一個master但
是還沒把這個事給客戶端說,客戶端不知道還認爲之前的master能用繼續向他寫數據
這個時候master上線了,由於有了一個master了他就被當作slave掛載到新的master了
本身之前的數據就清空了。再重新的master複製數據
複製代碼
一、解決腦裂:
能夠看下 這兩個配置
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1個slave,數據複製和同步的延遲不能超過10秒
若是說一旦全部的slave,數據複製和同步的延遲都超過了10秒鐘,那麼
這個時候,master就不會再接收任何請求了,因此就算丟數據也就最多損失10秒
二、解決異步複製
有了min-slaves-max-lag這個配置,就能夠確保說,一旦slave複製數據
和ack延時太長,就認爲可能master宕機後損失的數據太多了,那麼就拒
絕寫請求,這樣能夠把master宕機時因爲部分數據未同步到slave致使的數據丟失下降的可控範圍內
複製代碼
sdown 是主關宕機,就一個哨兵以爲master宕機了,就是主觀宕機。
odown是客觀宕機,就是多個哨兵以爲master宕機了
sdown達成條件就是,若是一個哨兵ping
master,超過了is-master-down-after-milliseconds指定的毫秒數就是主觀宕機
從sdown切換到odown就是一個哨兵在指定的時間裏,收到了quorum指定數
量的其餘哨兵也認爲那個master宕機了,就是客觀宕機了
複製代碼
哨兵之間是相互發現的,是經過redis的pub/sub系統實現的,每一個哨兵都
會往——sentinel_:hello這個channel裏發一個消息,這個時候其餘哨兵都
能夠消費這個信息,並感知其餘哨兵的存在
每隔兩秒鐘,每隔哨兵都會往本身監控的某個master+alaves對應的——sentinel_:hello channel裏
發送一個消息,消息內容就是本身的host、ip和runid還有就是對master的監控配置
每一個哨兵也會去監聽本身監控的每一個master+slaves對應的_sentinel_:hell channel,而後去感知到一樣在監聽這個master+slaves
的其餘哨兵存在。每一個哨兵還會跟其餘哨兵交換對master的監控配置,互相進行監控配置的同步
複製代碼
哨兵會負責自動糾正slave的一些配置,假如slave若是成爲了master的候選人,哨兵會確保slave在複製現有master的數據,若是slave鏈接到了一個錯誤的master上,好比故障轉移以後,那麼哨兵會確保他們鏈接到正確的master上
複製代碼
若是一個master唄認爲odown了,並且majority邵冰冰都容許了主備切換,
那麼某個哨兵就會執行主備切換操做,此時首先要選舉一個slave來
選舉 的時候會考慮slave的一些信息好比
一、跟master斷開鏈接的時長
二、slave的優先級
三、複製offset
四、run id
若是一個slave跟master斷開 鏈接已經超過了down-after-milliseconds的10倍,外加master宕機的時
長,那麼這個slave就不適合了(斷開這麼長時間你的數據還完整嗎)
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
接下來會對slave進行排序
(1)按照slave優先級進行排序,slave priority越低,優先級就越高
(2)若是slave priority相同,那麼看replica offset,哪一個slave複製了越多的數據,offset越靠後,優先級就越高
(3)若是上面兩個條件都相同,那麼選擇一個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號
複製代碼
哨兵切換完成後,會在本身本地更新生成最新的master配置,而後同步給其餘的哨兵,
同步的方式就是pub/sub消息機制
這個時候以前的version號就很重要了,由於各類消息都是經過一個channel去發佈和監聽的,
因此一個哨兵完成一次新的切換後,新的master配置
是跟着新的version號的
其餘哨兵都是根據版本號的大小來更新本身的master配置的
複製代碼