首先對于Redis叢集來講有三種模式,主從複制模式、Sentinel(哨兵)模式、Cluster模式。下面我們就來分别看一下Redis的三種叢集方案。
主從複制模式
首先來講,我們可以通過持久化的手段,來保證Redis在服務重新開機的情況下資料不會丢失,或者說是丢失的資料很少。因為持久化的的時候會把記憶體中的資料儲存到磁盤上,然後我們重新開機伺服器的時候會從磁盤上加載資料,這樣就保證了資料的持久化。但是由于資料是被存儲到單個的伺服器上,容易因為單點故障導緻數丢失的問題。
這個時候我們為了避免單點故障,就出現了将資料多複制幾份然後存儲到不同的伺服器上,這樣即便是有伺服器出現了故障,也不會導緻資料丢失。因為其他伺服器還是會提供服務。
為此,Redis提供了複制功能Replication。用來實作當一台資料庫的資料更新之後,自動将資料同步到其他伺服器資料庫上的操作。
在這個Replication 的概念中,将資料庫分成了兩種,一種是主資料庫(Master),一種是從資料庫(Slave)。
其中主資料庫主要完成對于資料的讀寫操作,其實主要是寫操作。當寫操作導緻資料庫的資料發生變化的時候,會自動通過同步機制将資料更新到從資料庫中。而從資料庫一般隻支援讀操作,并且接受來自主資料庫的資料同步操作,相當于寫。一個主資料庫可以有多個從資料庫,而一個從資料庫隻能有一個主資料庫。
主從複制的原理
圖檔來源網絡
- 從資料庫搭建好之後,連接配接到主資料庫,并且發送了一個SYNC指令。
- 主資料庫收到從資料庫發送的SYNC指令之後,開始執行BGSAVE指令用來生成RDB的快照檔案并且使用緩沖區記錄執行了BGSAVE指令之後的資料指令。
- 主資料庫的BGSAVE指令執行完成之後,向所有的從資料庫發送快照檔案,并且記錄在發送的過程中從緩存中同步的資料執行指令。
- 從資料庫在收到了新的虧按照之後就會丢棄掉所有的舊資料,然後載入新的快照。
- 主資料庫發送完快照之後,就會開始向從資料庫發送緩存區中的指令。
- 從資料庫按照快照載入完成之後,開始接收主資料庫發送的指令,并且執行來自主資料庫緩沖區中的指令。這個時候從資料庫就算是初始化完成了。
- 主資料庫執行了一條資料指令,就會向從資料庫發送相同的指令,從資料庫接收到指令之後執行,就完成了一條增量同步資料操作。
- 如果出現斷線重連,主資料庫将會将所有的增量資料與從資料庫進行同步。
也就是說當主從連接配接剛剛建立的時候,進行全量的資料同步操作。全量資料同步結束之後,如果有需要從資料庫可以發起全量同步,但是Redis提供的政策是無論如何都是先進行增量同步,如果沒有成功,才會進行全量同步。
主從複制的優缺點
優點
- 主從複制,主資料庫會主動的将資料同步到從資料庫中,可以有效的實作讀寫分離操作。這樣從資料庫就分擔了主資料庫的讀操作的壓力,因為從資料庫也會為用戶端提供讀操作服務,但是根據上面的邏輯,寫操作還是由主庫來完成。
- 從庫也可以接收其他從庫的連接配接請求和資料同步請求,也就是說從庫搭建好了之後不一定非要從主庫上去進行請求連接配接,也可以将請求連接配接與其他的從庫進行連接配接,這樣可以有效的減輕主庫的同步壓力。
- 主庫是以非阻塞的方式為從庫提供服務,是以在主從同步的過程中,用戶端仍然可以執行送出或者修改請求。
- 從庫也是同樣采用非阻塞的方式完成資料同步的,也就是說在同步資料的時候,如果用戶端有查詢請求進入,Redis從庫依然會傳回之前的資料。
缺點
- Redis 由于不具備自動容災和恢複的能力,主庫和從庫的當機都會導緻部分讀寫請求的失敗,這個是無可避免的,因為如果目前機器突然當機,那麼目前機器上所有的請求都将會失敗,是以需要等到機器恢複或者是進行IP切換之後才能正常的通路,而這個操作在沒有特殊處理手段的時候都是由人工來完成的。
- 如果出現了多個從庫當機重新開機的時候,不能同時進行重新開機,因為資料同步機制會使得主庫的IO劇增,導緻主庫當機。
- Redis很難支援線上擴容的操作,當叢集的容量增加到一定程度之後,線上擴容機制就會變的非常的複雜。
Sentinel(哨兵)模式
根據上面的分析,主從複制模式,當主庫當機之後,需要手動的将其中一台伺服器切換為主伺服器,這就需要人力的幹預,不僅費時費力,還會導緻一部分損失。是以一般不推薦這種方式,當然在資料較少的情況下也可以采用。
為了解決上面這種問題就出現了哨兵模式。哨兵模式是一種特殊的模式,首先Redis中提供了哨兵的指令,并且這裡所說的哨兵是一個獨立的程序,作為程序來講,它具有獨立運作的特點就相當于我們的一個應用程式。而哨兵模式的原理就是哨兵通過發送指令的方式,等待Redis伺服器響應,進而實作對于Redis執行個體的運作監控操作。如圖所示。圖檔來源于網絡
哨兵模式的作用就是要讓哨兵發送指令,讓Redis服務能夠響應并且傳回其對應的運作狀态。并且當哨兵監聽到主庫當機之後,會自動的将從庫提升為主庫,然後通過Redis的釋出訂閱模式将修改釋出給其他服務的配置,進而實作主庫的切換。
但是這裡有個問題如果當我們的哨兵程序被卡死之後,沒有辦法進行監控了,那麼我們之前遇到的問題還是得需要人工來解決。這個時候就有人提出了多哨兵模式,如上圖所示。
假設主庫當機了,按照之前的說法,哨兵會立即知道主庫當機,這個時候僅僅隻是哨兵知道主庫當機了,從庫還在等待主庫同步資料呢,然後當其他的哨兵同樣也檢測到了主庫不能用了,這個時候就所有的哨兵都要進行投票了,從剩下的從庫中選擇一個從庫将其設定為主庫了。設定完成之後就會通過釋出訂閱将消息發送到其他從庫。然後進行主庫配置的切換。那麼哨兵模式究竟是如何工作呢?
哨兵模式的工作機制
- 對于每個哨兵來講,其對應的程序會在規定的時間内向叢集中的Master伺服器、Slave伺服器、以及其他哨兵發送一個消息。
- 如果在指定的時間内沒有收到響應的消息,則會被目前這個哨兵程序标記為對應的服務已經下線了。
- 如果這個時候被标記下線的正好是一個Master伺服器,那麼當其他的哨兵線程也監聽到了同樣的下線消息之後,那麼Master伺服器就确認已經下線了。
- 那麼這個時候,就要将叢集中的一個Slave節點更新成Master節點。當然這裡需要注意點。如果在此過程中隻有少部分的哨兵程序監聽到了Master下線,那麼哨兵就會修改對于Master伺服器的監聽時間,可能從10秒一次變成1秒一次的監聽頻率。
- 如果這個時候監聽到的Master并沒有出現問題。那麼就會将Master的下線标志移除。叢集進入正常狀态。
這裡需要注意一個就是哨兵模式對于Redis叢集的選主操作。其實這個我們可以參考Zookeeper叢集的選主操作,其采用的都是Paxos算法。有興趣的讀者可以自己研究,筆者也會在後續的分享中介紹與之相關的内容。
從上面的機制來看,哨兵模式要比主從複制模式要進階一點,至少是可以進行主從切換,提升了叢集的健壯性。
Cluster 叢集模式
Cluster叢集是Redis官方提供的模式,也是在實際開發中使用的比較多的一種模式。在Redis哨兵模式中基本上是實作了高可用、讀寫分離等。但是在哨兵模式下還是沒有解決主從同步模式中的資料同步帶來的資料備援問題。因為在這兩種模式下,主庫和從庫存儲的都是相同的資料,會導緻大量存儲的浪費。而Redis官方提供的Cluster模式就實作了Redis資料的分布式存儲,也就是說每個節點上存儲的是不同的資料。
這樣就不會出現資料備援,存儲資源浪費的問題,同時也減少了由于主從同步而帶來的IO資源消耗等問題。
如圖所示,圖中的每個Redis節點都是互相連通的,并且用戶端可以與其中的任意節點進行連接配接,并且可以通路到其中任意節點上的資料,并且對資料進行讀寫操作。
這種模式将整個的Redis叢集看作一個存儲整體,并且每個節點又可以獨立存儲,在提升了叢集可用性的同時,既沒有引入主從複制的消耗,也不會出現哨兵模式所帶來的性能消耗。可以說将叢集存儲的概念利用到了極緻。當然有優勢就有劣勢,這種模式在資料節點較少的情況下幾乎是與主從模式性能相仿,而且在有些保證資料高可用的場景下甚至不如主從複制。
因為這種模式每個節點中存儲的隻是一部分資料,而如果在節點較少的情況下,一個節點當機,就會導緻對應節點上的資料丢失。是以有點得不償失。
總結
在實際開發中,我們要根據自己具體的業務需求來選擇合适的叢集模式。根據上面的内容我們也知道,對于技術選擇,沒有最好隻有最合适。