1. 程式人生 > 實用技巧 >3------叢集篇

3------叢集篇

主從同步

當主節點(Master)掛掉的時候,運維讓從節點(slave)過來接管,服務就可以繼續,否則主節點需要經過資料恢復和重啟的過程。

CAP原理

分散式儲存的理論基石

  1. C:Consistent,一致性
  2. A:Availability,可用性
  3. P:Partition tolerance,分割槽容忍性

分散式系統的節點往往都是分佈在不同的機器上進行網路隔離的,網路分割槽。

網路分割槽:兩個節點之間不能通訊

網路分割槽發生時,一致性和可用性兩難全

最終一致

Redis的主從資料是非同步同步的,所以分散式系統並不滿足一致性,但是滿足可用性

但是滿足最終一致性,因為網路恢復後,從節點會採用各種策略努力追趕恢復的。

Redis同步支援主從同步和從從同步

增量同步

主節點將修改主節點狀態的指令 寫入 下圖環狀的buffer陣列當中,迴圈一直覆蓋寫。

從節點一直從上面讀指令,達到和主節點一致的狀態、、、並且返回自己複製到哪兒了

但是遇到網路問題,那麼指令就會被覆蓋掉

這個時候就需要快照同步。

快照同步

在主節點上來一次bgsave,將當前記憶體的資料全部快照到磁碟檔案中

然後,再將快照檔案傳送給從節點。從節點來一個全量載入

載入之前先要將當前記憶體的資料清空,載入完畢後通知主節點繼續進行增量同步

但是!!!!這個時候,主節點的buffer還是在一直複製的,如果快照時間過長或者buffer的太小,那麼就會造成快照死迴圈。

增加從節點

當從節點剛剛加到叢集中,必須來一次快照同步,才能進行增量同步

無盤複製

主要指快照同步

主節點直接通過套接字將快照內容傳送到從節點

主節點會一邊遍歷記憶體,一邊將序列化的內容傳送到從節點,從節點將收到的內容載入到磁碟,最後再進行一次載入。

wait指令

Redis的複製是非同步的,wait指令可以讓非同步複製變身同步複製,確保系統的強一致性

set key value
wait 1 0

兩個引數:第一個引數從節點的數量;第二個引數是時間t。

等待wait指令之前的所有寫操作同步到N個從節點,最多等待時間t,等待從節點同步。如果t=0,表示無限等待直到N個從節點同步完成。

假設此時出現了網路分割槽,wait指令第二個引數為0,那麼redis伺服器就失去了可用性

Sentinel

哨兵系統,主節點壞了,自動將從節點升級為主節點,不用手動

Sentinel負責持續監控主從節點的健康,當主節點掛了,自動選擇一個最優的從節點切換為主節點。

客戶端連線叢集,會首先連線Sentinel,通過Sentinel來查詢主節點的地址,然後再連線主節點進行資料互動。

當主節點故障了,客戶端會重新想Senatinel要地址,Sentinel會將最新的主節點告訴客戶端。

當主節點恢復之後,自動稱為從節點。

訊息丟失

Sentinel無法保證資料不丟失,但是儘量保證資訊少丟失

限制主從延遲不要太大

# 保證至少一個從節點正常複製
min-slave-to-write 1

#什麼是正常複製,那就是每過10s收到從節點的反饋
min-slaves-max-lag 10

Sentinel基本用法

客戶端通過Sentinel來發現從節點的地址,然後再通過地址建立相應的連線。

Sentinel預設埠為26379

客戶端如何知道地址發生改變?

------建立連線的時候進行主節點地址變更判斷

連線池建立新連線時,會去查詢主節點地址,然後跟記憶體中的主節點地址進行比對,如果變更了,就斷開所有連線,重新使用新地址進行連線。如果舊的主節點掛掉了,那麼所有正在使用的連線都會關閉,然後在重連時就會用上新地址

Codis分而治之

單個Redis記憶體不宜過大,記憶體太大導致rdb檔案過大,進一步導致主從同步時全量同步時間過長,在例項重啟恢復時也會消耗很長的資料載入時間。

Codis:將眾多小記憶體的Redis例項整合起來,將分佈在多臺機器上的眾多CPU核心的計算能力聚集在一起,完成海量資料儲存和高併發讀寫操作

當客戶端向Codis傳送指令時,Codis負責將指令轉發到後面的Redis例項來致性,並且將結果返回給客戶端。

Codis是一個轉發代理中介軟體,可以啟動多個Codis例項,供客戶端使用,每個Codis節點都是對等的。

還可以起到容災功能

Codis分片原理

Codis負責將特定的key轉發到特定的Redis例項中

Codis預設將所有的key劃分為1024個槽位,將key進行hash,然後得到槽位。然後到相應的redis例項當中查詢

不同的Codis例項之間槽位關係如何同步?

利用zookeeper,儲存Codis例項和槽位之間的通訊,多個Codis之間同步。

擴容

Codis本來只有一個Redis例項,接下來新加了一個,那麼就會將一半的槽位分給新的節點。

利用SLOTSSCAN指令掃描一個槽下的所有key,然後挨個遷移。

遷移的時候,Codis的槽有可能還在接收新的key-----------------------那麼,COdis接收到位於正在遷移槽位中的key後,會立即強制對當前的單個key進行遷移,遷移完成後,再將請求轉發到新的Redis例項中

自動均衡

Codis會檢視每個Redis對應的槽位,然後自動均衡負載

Codis的代價

  1. 不支援事務
  2. 遷移會變得困難
  3. 網路開銷變大,畢竟多走了一個網路節點

Codis的優點

簡單

mget指令的操作過程

架構變遷

畢竟不是官方的,老是隨著官方的redis改變

Codis尷尬

不是親生的

Codis後臺管理

一個很友好的後臺web介面

Cluster

redis Cluster去中心化的叢集方案

叢集由三個Redis節點組成,每個節點負責整個叢集的一部分資料,每個節點負責的資料多少可能不一樣。二進位制協議通訊

將資料劃分為16384個槽位,每個節點負責其中一部分槽位。

客戶端來連線叢集,會得到一份叢集的槽位配置資訊,然後通過這個配置資訊去查詢完事了。

客戶端需要快取槽位的資訊,可能客戶端和伺服器儲存槽位的資訊不一致的情況,這個時候還需要校準。

Redis Cluster的每個節點會將叢集的配置資訊持久化到配置檔案中,所以必須保證配置檔案時可寫的,而且儘量不要依靠人工修改配置檔案

槽位定位方法

將key進行hash,然後將雜湊值與槽位進行雜湊

Redis Cluster允許將使用者強制把某個key掛在特定的槽位上

跳轉

當節點發現客戶端的請求中的槽位並不歸屬自己管,就會給客戶端傳送一個帶跳轉地址的資訊,讓客戶端去連線這個節點獲取資料

遷移

從源節點獲取內容---存區目標節點------從源節點中刪除

整個轉移過程中,轉移是一步一步的,假如單個key過大,那會引起卡頓的。

客戶端首先會訪問舊節點,找到了還好,找不到舊節點會重定向;----客戶端向新節點詢問下Asking,然後再致性原先的操作指令。Asking指令避免重定向迴圈。

容錯

每個節點設定幾個從節點,當主節點發生故障時,叢集就會自動升級從節點;同時允許若干個主節點發生故障

網路抖動

有時候,有些節點突然失聯,突然又連線上了,Redis Cluster給一個失聯的時間,超過這個時間就表示失聯了;主從切換。

cluster-node-timeout

可能下線和確定下線

Redis cluster是去中心化的,一個節點認為某個節點失聯了,並不管用,只有大多數節點都認定某個節點失聯了,叢集才認識該節點需要進行主從切換來容錯。

比如:某個節點發現某個節點失聯了(PFail),它會將這條資訊向整個叢集廣播,其它節點就可以收到這點的失戀資訊。如果收到了某個節點失聯的數量已經達到了叢集的大多數,就可以標記這個節點失聯。Fail

Cluster基本用法

匯入redis-py-cluster模組才可以使用

cluster不支援事務:Cluster的mget方法比redis要慢很多,被拆分成了多個get指令;Cluster的rename方法不再是原子的,它需要將資料從源節點轉移到目標節點。

槽位遷移感知

客戶端儲存了槽位和節點的對映關係表,它需要及時得到更新。

moved指令:客戶端請求了錯誤的節點,節點指揮客戶端重定向到正確的節點上。並且重新整理客戶端的配置資訊

asking指令:再遷移時傳送的指令。

不過上述的兩個指令都是重試指令,需要限制重試的次數。高於這個次數就報錯

叢集變更感知

當服務節點變更時,客戶端應該立即得到通知以實時重新整理自己的節點關係表。那麼客戶端是如何知道的

  1. 目標節點掛掉了,客戶端丟擲ConnectionError指令,緊接著隨機挑一個節點來重試,然後提供moved指令進行重試
  2. 運維手動修改叢集資訊,將主節點切換到其它節點,並將舊的主節點移除出叢集,這時打在舊節點上的指令會受到ClusterDown錯誤,然後客戶端關閉所有的連線,清空槽位對映關係表,重新嘗試初始化節點資訊