主從複製,就是主機數據更新後根據配置和策略,自動同步到備機的master/slaver機制,Master以寫爲主,Slave以讀爲主python
讀寫分離,性能擴展 容災快速恢復git
當一個從數據庫啓動後,會向主數據庫發送SYNC命令。同時主數據庫接收到SYNC命令後會開始在後臺保存快照(即RDB持久化的過程),並將保存快照期間接收到的命令緩存 起來當快照完成後,Redis會將快照文件和全部緩存的命令發送給從數據庫。從數據庫收到後, 會載入快照文件並執行收到的緩存的命令。以上過程稱爲複製初始化。複製初始化結束後, 主數據庫每當收到寫命令時就會將命令同步給從數據庫,從而保證主從數據庫數據一致。
當主從數據庫之間的鏈接斷開重連後,Redis 2.6以及以前的版本會從新進行復制初始化(即主數據庫從新保存快照並傳送給從數據庫),即便從數據庫能夠僅有幾條命令沒有收到,主數據庫也必需要將數據庫裏的全部數據從新傳送給從數據庫。這使得主從數據庫斷 線重連後的數據恢復過程效率很低下,在網絡環境很差的時候這一問題尤爲明顯。Redis2.8 版的一個重要改進就是斷線重連可以支持有條件的增量數據傳輸,當從數據庫從新鏈接上主數據庫後,主數據庫只須要將斷線期間執行的命令傳送給從數據庫從而大大提升Redis 複製的實用性。github
複製同步階段會貫穿整個主從同步過程的始終,直到主從關係終止爲止。在複製的過程當中,快照不管在主數據庫仍是從數據庫中都起了很大的做用,只要執行 複製就會進行快服即便咱們關閉了 RDB方式的持久化(經過刪除全部save參數)。 redis
樂觀複製Redis採用了樂觀複製(optimistic replication)的複製策略,容忍在必定時 間內主從數據庫的內容是不一樣的,可是二者的數據會最終同步。具體來講,Redis在主 從數據庫之間複製數據的過程自己是異步的,這意味着,主數據庫執行完客戶端請求的命令後會當即將命令在主數據庫的執行結果返回給客戶端,並異步地將命令同步給 從數據庫,而不會等待從數據庫接收到該命令後再返回給客戶端。這一特性保證了啓 用複製後主數據庫的性能不會受到影響,但另外一方面也會產生一個主從數據庫數據不 一致的時間窗口,當主數據庫執行了一條寫命令後,主數據庫的數據已經發生的變更,然而在主數據庫將該命令傳送給從數據庫以前,若是兩個數據庫之間的網絡鏈接斷開 了,此時兩者之間的數據就會是不一致的。從這個角度來看,主數據庫是沒法得知某 個命令最終同步給了多少個從數據庫的,不過Redis提供了兩個配置選項來限制只有 當數據至少同步給指定數量的從數據庫時,主數據庫纔是可寫的.算法
數據庫不只能夠接收主數據庫的同步數據,本身也能夠同時做爲主數據庫存在,造成相似圖的結構,數據庫
經過複製能夠實現讀寫分離,以提升服務器的負載能力。在常見的場景中(如電子商務網站),讀的頻率大於寫,當單機的Redis沒法應付大量的讀請求時(尤爲是較耗資源的 請求,如SORT命令等)能夠經過複製功能創建多個從數據庫節點,主數據庫只進行寫操做,而從數據庫負責讀操做。這種一主多從的結構很適合讀多寫少的場景,而當單個的主數據庫不可以知足需求時,就須要使用Redis 3.0推出的集羣功能,緩存
另外一個相對耗時的操做是持久化,爲了提升性能,能夠經過複製功能創建一個(或若干個)從數據庫,並在從數據庫中啓用持久化,同時在主數據庫禁用持久化。當從數據庫崩潰重啓後主數據庫會自動將數據同步過來,因此無需擔憂數據丟失。
然而當主數據庫崩潰時,狀況就稍顯複雜了。手工經過從數據庫數據恢復主數據庫數據時,須要嚴格按照如下兩步進行。
在從數據庫中使用SLAVEOF NO ONE命令將從數據庫提高成主數據庫繼續服務。啓動以前崩潰的主數據庫,而後使用SLAVEOF命令將其設置成新的主數據庫的從 數據庫,便可將數據同步回來。
注意當開啓複製且主數據庫關閉持久化功能時,必定不要使用Supervisor以及相似 的進程管理工具令主數據庫崩潰後自動重啓。一樣當主數據庫所在的服務器因故關閉 時,也要避免直接從新啓動。這是由於當主數據庫從新啓動後,由於沒有開啓持久化功能,因此數據庫中全部數據都被清空,這時從數據庫依然會從主數據庫中接收數據, 使得全部從數據庫也被清空,致使從數據庫的持久化失去意義。
不管哪一種狀況,手工維護從數據庫或主數據庫的重啓以及數據恢復都相對麻煩,好在 Redis提供了一種自動化方案哨兵來實現這一過程,避免了手工維護的麻煩和容易出錯的問題,服務器
這種狀況下一旦主機宕機,整個寫服務都會癱瘓,所以爲了不羣龍無首的局面,咱們能夠對配置進行優化 這裏咱們先採用薪火相傳的模式.網絡
上一個slave能夠是下一個slave的Master,slave一樣能夠接收其餘slaves的鏈接和同步請求,那麼該slave做爲了鏈條中下一個的master, 能夠有效減輕master的寫壓力,去中心化下降風險。中途變動轉向:會清除以前的數據,從新創建拷貝最新的
風險:一旦某個slave宕機,後面的slave都無法備份.異步
當一個master宕機後,後面的slave能夠馬上升爲master,其後面的slave不用作任何修改。
主機宕機
用 slaveof no one 將從機變爲主機。
當原來的master又復活以後,後面的slave和原來的mamaster就不要緊了
當原來的master又復活以後,後面的slave和原來的master就不要緊了
Redis中複製的原理和使用方式,在一個典型的一主多從的Redis系統中, 從數據庫在整個系統中起到了數據冗餘備份和讀寫分離的做用。當主數據庫遇到異常中斷服務後,開發者能夠經過手動的方式選擇一個從數據庫來升格爲主數據庫,以使得系統可以繼續提供服務。然而整個過程相對麻煩且須要人工介入,難以實現自動化。爲此Redis 2.8中提供了哨兵工具來實現自動化的系統監控和故障恢復功能。
注意Redis 2.6版也提供了哨兵工具,但此時的哨兵是1.0版,存在很是多的問題, 在任何狀況下都不該該使用這個版本的哨兵。這裏說的哨兵都是Redis2.8以後的
顧名思義,哨兵的做用就是監控Redis系統的運行情況。它的功能包括如下兩個。
(1) 監控主數據庫和從數據庫是否正常運行。
(2) 主數據庫出現故障時自動將從數據庫轉換爲主數據庫。
配置哨兵監控一個系統時,只須要配置其監控主數據庫便可,哨兵會自動發現全部複製該主數據庫的從數據庫
自定義的/myredis目錄下新建sentinel.conf文件
其中— sdown表示哨兵主觀認爲主數據庫中止服務了,而+odown則表示哨兵客觀認爲主數據庫中止服務了,關於主觀和客觀的區別後文會詳細介紹。此時哨兵開始執行故障恢復, 即挑選一個從數據庫,將其升格爲主數據庫。+try -faiover 表示哨兵開始進行故障恢復,+failover -end 表示哨兵完成故障恢復,期間涉及的內容比較複雜,包括領頭哨兵的選舉、備選從數據庫的選擇等,放到後面介紹,此處只須要關注最後3條輸出。+switch-master表示主數據庫從6379端口遷移 到6381端口,即6381端口的從數據庫被升格爲主數據庫,同時兩個+slave則列出了新的主數據庫的兩個從數據庫,端口分別爲6380和6379。其中6379就是以前中止服務的主數據庫,可見哨兵並無完全清除中止服務的實例的信息,這是由於中止服務的實例有 能會在以後的某個時間恢復服務,這時哨兵會讓其從新加入進來,因此當實例中止服務後, 哨兵會更新該實例的信息,使得當其從新加入後能夠按照當前信息繼續對外提供服務。此例中6379端口的主數據庫實例中止服務了,而6381端口的從數據庫已經升格爲主數據庫, 當6379端口的實例恢復服務後,會轉變爲6380端口實例的從數據庫來運行,因此哨兵將6379端口實例的信息修改爲了6381端口實例的從數據庫。 故障恢復完成後,可使用Redis命令行客戶端從新檢查6379和6381兩個端口上的 實例的複製信息:
-sdown表示實例6379已經恢復服務了(與+sdown相反i同時+convert-to-slave 表示將6379端口的實例設置爲6381端口實例的從數據庫。
一個哨兵進程啓動時會讀取配置文件的內容,經過以下的配置找出須要監控的主數據庫:
sentinel monitor master~name ip redis-port quorum
其中master-name是一個由大小寫字母、數字和組成的主數據庫的名字,由於考慮到故障恢復後當前監控的系統的主數據庫的地址和端口會產生變化,因此哨兵提供了命令能夠經過主數據庫的名字獲取當前系統的主數據庫的地址和端口號.ip表示當前系統中主數據庫的地址,而redis-port則表示端口號。
quorum用來表示執行故障恢復操做前至少須要幾個哨兵節點贊成,後文會詳細介紹。 一個哨兵節點能夠同時監控多個Redis主從系統,只須要提供多個sentinel monitor
配置便可,例如:
sentinel monitor mymaster 127.0.0.1 6379 2 sentinel monitor othermaster 192.168.1.3 6380 4
同時多個哨兵節點也能夠同時監控同一個Redis主從系統,從而造成網狀結構。
配置文件中還能夠定義其餘監控相關的參數,每一個配置選項都包含主數據庫的名字使 得監控不一樣主數據庫時可使用不一樣的配置參數。例如:
sentinel down-after-milliseconds mymaster 60000 sentinel down-after-milliseconds othermaster 10000
上面的兩行配置分別配置了 mymaster 和othermaster 的 down-after-milliseconds 選項分別爲60000和10000。
哨兵啓動後,會與要監控的主數據庫創建兩條鏈接,這兩個鏈接的創建方式與普通的Redis客戶端無異。其中一條鏈接用來訂閱該主數據的_Sentinel_:hello頻道以獲取
其餘一樣監控該數據庫的哨兵節點的信息,另外哨兵也須要按期向主數據庫發送INFO等 命令來獲取主數據庫自己的信息,客戶端的鏈接進入訂閱模式時就不 能再執行其餘命令了,因此這時哨兵會使用另一條鏈接來發送這些命令和主數據庫的鏈接創建完成後,哨兵會定時執行下面3個操做。
(1) 每10秒哨兵會向主數據庫和從數據庫發送INFO命令。
(2) 每2秒哨兵會向主數據庫和從數據庫的_sentinel_:hello頻道發送本身的 信息。
(3) 每1秒哨兵會向主數據庫、從數據庫和其餘哨兵節點發送PING命令。
這3個操做貫穿哨兵進程的整個生命週期中,很是重要,能夠說了解了這3個操做的 意義就可以瞭解哨兵工做原理的一半內容了。下面分別詳細介紹。
首先,發送INFO命令使得哨兵能夠得到當前數據庫的相關信息包括運行ID、複製 信息等)從而實現新節點的自動發現。前面說配置哨兵監控Redis主從系統時只須要指定主數據庫的信息便可,由於哨兵正是藉助INFO命令來獲取全部複製該主數據庫的從數據庫信息的。啓動後,哨兵向主數據庫發送INFO命令,經過解析返回結果來得知從數據庫列表,然後對每一個從數據庫一樣創建兩個鏈接,兩個鏈接的做用和前文介紹的與主數據庫 創建的兩個鏈接徹底一致。在此以後,哨兵會每10秒定時向己知的全部主從數據庫發送INFO命令來獲取信息更新並進行相應操做,好比對新增的從數據庫創建鏈接並加入監控列表,對主從數據庫的角色變化(由故障恢復操做引發)進行信息更新等。接下來哨兵向主從數據庫的_Sentinel_:hello 頻道發送信息來與一樣監控該數 據庫的哨兵分享本身的信息。發送的消息內容爲:
<哨兵的地址 >,<哨兵的端口 >, <哨兵的運行ID>,<哨兵的配置版本>,<主數據庫的名字>,<主數據庫的地址>, <主數據庫的端口>, <主數據庫的配置版本>
能夠看到消息包括的哨兵的基本信息,以及其監控的主數據庫的信息。
哨兵會訂閱每一個其監控的數據庫的_Sentinel_:hell0頻道,因此當其餘哨兵收到消息 後,會判斷髮消息的哨兵是否是新發現的哨兵。若是是則將其加入已發現的哨兵列表中並 建立一個到其的鏈接(與數據庫不一樣,哨兵與哨兵之間只會建立一條鏈接用來發送PING 命令,而不須要建立另一條鏈接來訂閱頻道,由於哨兵只須要訂閱數據庫的頻道便可實 現自動發現其餘哨兵)。同時哨兵會判斷信息中主數據庫的配置版本,若是該版本比當前記 錄的主數據庫的版本高,則更新主數據庫的數據。配置版本的做用會在後面詳細介紹。 實現了自動發現從數據庫和其餘哨兵節點後,哨兵要作的就是定時監控這些數據庫 和節點有沒有中止服務。這是經過每隔必定時間向這些節點發送PING命令實現的。時間 間隔與 down-after-milliseconds 選項有關當down-after-milliseconds 的值 小於1秒時哨兵會每隔down-after-milliseconds指定的時間發送一次PING命令,當down-after-milliseconds的值大於1秒時,哨兵會每隔1秒發送一次PING命令。 例如:
//每隔1秒發送一次PING命令 sentinel down-after-milliseconds mymaster 60000 //每隔600毫秒發送一次PING命令 sentinel down-after-milliseconds othermaster 600
當超過down-after-mill seconds選項指定時間後,若是被PING的數據庫或節點仍然未進行回覆,則哨兵認爲其主觀下線( subjectively down)。主觀下線表示從當前的哨兵進程看來,該節點已經下線。若是該節點是主數據庫,則哨兵會進一步判斷是否須要對其進行故障恢復:哨兵發送SENTINEL is-master-down-by-addr命令詢問其餘哨兵節點以瞭解他們是否也認爲該主數據庫主觀下線,若是達到指定數量時,哨兵會認爲其客觀 下線(objectively down),並選舉領頭的哨兵節點對主從系統發起故障恢復。這個指定數量 即爲前文介紹的quorum參數。例如,下面的配置:
sentinel monitor mymaster 127.0.0.1 6379 2
該配置表示只有當至少兩個Sentinel節點(包括當前節點)認爲該主數據庫主觀下線時,當前哨兵節點纔會認爲該主數據庫客觀下線。進行接下來的選舉領頭哨兵步驟。
雖然當前哨兵節點發現了主數據庫客觀下線,須要故障恢復,可是故障恢復須要由領頭的哨兵來完成,這樣能夠保證同一時間只有一個哨兵節點來執行故障恢復。選舉領頭哨兵的過程使用了Raft算法,具體過程以下。
(1)發現主數據庫客觀下線的哨兵節點(下面稱做A)向每一個哨兵節點發送命令,要 求對方選本身成爲領頭哨兵。
(2)若是目標哨兵節點沒有選過其餘人,則會贊成將A設置成領頭哨兵。
(3)若是A發現有超過半數且超過quorum參數值的哨兵節點贊成選本身成爲領頭哨兵,則A成功成爲領頭哨兵。
(4)當有多個哨兵節點同時參選領頭哨兵,則會出現沒有任何節點當選的可能。此時 每一個參選節點將等待一個隨機時間從新發起參選請求,進行下一輪選舉,直到選舉成功。 具體過程能夠參考Raft算法的過程http://raftconsensus.github.io/。由於要成爲領頭哨兵 必須有超過半數的哨兵節點支持,因此每次選舉最多隻會選出一個領頭哨兵。
選出領頭哨兵後,領頭哨兵將會開始對主數據庫進行故障恢復。故障恢復的過程相對 簡單,具體以下。 首先領頭哨兵將從中止服務的主數據庫的從數據庫中挑選一個來充當新的主數據庫。 挑選的依據以下。
(1) 全部在線的從數據庫中,選擇優先級最高的從數據庫。優先級能夠經過 slave-priority選項來設置。
(2) 若是有多個最高優先級的從數據庫,則複製的命令偏移量(見8.1.7節)越大(即 複製越完整)越優先。
(3) 若是以上條件都同樣,則選擇運行ID較小的從數據庫。 選出一個從數據庫後,領頭哨兵將向從數據庫發送SLAVEOF NO ONE命令使其升格爲主數據庫。然後領頭哨兵向其餘從數據庫發送SLAVEOF命令來使其成爲新主數據庫的從數據庫。最後一步則是更新內部的記錄,將已經中止服務的舊的主數據庫更新爲新的主數據庫的從數據庫,使得當其恢復服務時自動以從數據庫的身份繼續服務。
哨兵以獨立進程的方式對一個主從系統進行監控,監控的效果好壞與否取決於哨兵的 視角是否有表明性。若是一個主從系統中配置的哨兵較少,哨兵對整個系統的判斷的可靠 性就會下降。極端狀況下,當只有一個哨兵時,哨兵自己就可能會發生單點故障。總體來 講,相對穩妥的哨兵部署方案是使得哨兵的視角儘量地與每一個節點的視角一致,即:
(1)爲每一個節點(不管是主數據庫仍是從數據庫)部署一個哨兵;
(2)使每一個哨兵與其對應的節點的網絡環境相同或相近。
這樣的部署方案能夠保證哨兵的視角擁有較高的表明性和可靠性。舉例一個例子. 當網絡分區後,若是哨兵認爲某個分區是主要分區即意味着從每一個節點觀察,該分區均爲主分區。
同時設置quorum的值爲N/2+1 (其中N爲哨兵節點數量),這樣使得只有當大部分哨兵節點贊成後纔會進行故障恢復。
當系統中的節點較多時,考慮到每一個哨兵都會和系統中的全部節點創建鏈接,爲每一個 節點分配一個哨兵會產生較多鏈接,尤爲是當進行客戶端分片時使用多個哨兵節點監控多 個主數據庫會由於Redis不支持鏈接複用而產生大量冗餘鏈接,具體能夠見此issue: https://github.com/antirez/redis/issues/2257 ; 同時若是 Redis 節點負載較高,會在必定程度上影響其對哨兵的回覆以及與其同機的哨兵與其餘節點的通訊。因此配置哨兵時還須要根據 實際的生產環境狀況進行選擇。