Redis主從複製和高可用方案

Redis 安裝

下載地址:https://redis.io/download
tar xzf redis-5.0.3.tar.gz
cd redis-5.0.3
make

啓動腳本

src/redis-server

主從複製方案

從的配置文件修改

#replicaof <masterip> <masterport>
replicaof 127.0.0.1 6379
#masterauth <master-password>
masterauth 123456
重啓從的redis

從日誌輸出

10896:S 25 Feb 2019 16:12:33.258 * Full resync from master: e3dba16f7d2f755f59a7307ad0955a9f584f5825:0
10896:S 25 Feb 2019 16:12:33.337 * MASTER <-> REPLICA sync: receiving 175 bytes from master
10896:S 25 Feb 2019 16:12:33.337 * MASTER <-> REPLICA sync: Flushing old data
10896:S 25 Feb 2019 16:12:33.338 * MASTER <-> REPLICA sync: Loading DB in memory
10896:S 25 Feb 2019 16:12:33.338 * MASTER <-> REPLICA sync: Finished with success

主日誌輸出

6364:M 25 Feb 2019 16:12:33.337 * Synchronization with replica 127.0.0.1:6380 succeeded

通過cli連接主的redis 添加內容

set name zhang

通過從的查找

get name
“zhang”

高可用

方案一 哨兵

  • 環境準備

redis信息

master:6739
slave 1:6780
slave 2:6781

sentinel

sentinel1 : 26739
sentinel2 : 26780
sentinel3 : 26781

  • 配置信息

master:

port 6379
masterauth 123456
requirepass “123456”

slave1:

port 6380
replicaof 127.0.0.1 6379
masterauth 123456
requirepass “123456”

slave2:

port 6381
replicaof 127.0.0.1 6379
masterauth 123456
requirepass “123456”

sentinel1 :

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster 123456

注:這一行代表sentinel監控的master的名字叫做mymaster,地址爲127.0.0.1:6379。這個2代表,當集羣中有2個sentinel認爲master死了時,才能真正認爲該master已經不可用了。(sentinel集羣中各個sentinel也有互相通信,通過gossip協議)

sentinel2 :

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster 123456

sentinel3 :

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster 123456

  • 啓動測試

依次啓動master、slave、sentinel

啓動後停止master節點,可以看到slave1切換爲master節點。再次啓動master,變爲slave2.

sentinel 配置說明

參考文檔:https://segmentfault.com/a/1190000002680804

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5

上面的配置項配置了兩個名字分別爲mymaster和resque的master,配置文件只需要配置master的信息就好啦,不用配置slave的信息,因爲slave能夠被自動檢測到(master節點會有關於slave的消息)。需要注意的是,配置文件在sentinel運行期間是會被動態修改的,例如當發生主備切換時候,配置文件中的master會被修改爲另外一個slave。這樣,之後sentinel如果重啓時,就可以根據這個配置來恢復其之前所監控的redis集羣的狀態。

sentinel monitor mymaster 127.0.0.1 6379 2

這一行代表sentinel監控的master的名字叫做mymaster,地址爲127.0.0.1:6379,行尾最後的一個2代表什麼意思呢?我們知道,網絡是不可靠的,有時候一個sentinel會因爲網絡堵塞而誤以爲一個master redis已經死掉了,當sentinel集羣式,解決這個問題的方法就變得很簡單,只需要多個sentinel互相溝通來確認某個master是否真的死了,這個2代表,當集羣中有2個sentinel認爲master死了時,才能真正認爲該master已經不可用了。(sentinel集羣中各個sentinel也有互相通信,通過gossip協議)。

除了第一行配置,我們發現剩下的配置都有一個統一的格式:

sentinel <option_name> <master_name> <option_value>

接下來我們根據上面格式中的option_name一個一個來解釋這些配置項:

  • down-after-milliseconds
    sentinel會向master發送心跳PING來確認master是否存活,如果master在“一定時間範圍”內不迴應PONG 或者是回覆了一個錯誤消息,那麼這個sentinel會主觀地(單方面地)認爲這個master已經不可用了(subjectively down, 也簡稱爲SDOWN)。而這個down-after-milliseconds就是用來指定這個“一定時間範圍”的,單位是毫秒。

不過需要注意的是,這個時候sentinel並不會馬上進行failover主備切換,這個sentinel還需要參考sentinel集羣中其他sentinel的意見,如果超過某個數量的sentinel也主觀地認爲該master死了,那麼這個master就會被客觀地(注意哦,這次不是主觀,是客觀,與剛纔的subjectively down相對,這次是objectively down,簡稱爲ODOWN)認爲已經死了。需要一起做出決定的sentinel數量在上一條配置中進行配置。

  • parallel-syncs
    在發生failover主備切換時,這個選項指定了最多可以有多少個slave同時對新的master進行同步,這個數字越小,完成failover所需的時間就越長,但是如果這個數字越大,就意味着越多的slave因爲replication而不可用。可以通過將這個值設爲 1 來保證每次只有一個slave處於不能處理命令請求的狀態。

其他配置項在sentinel.conf中都有很詳細的解釋。
所有的配置都可以在運行時用命令SENTINEL SET command動態修改。

Sentinel的“仲裁會”

前面我們談到,當一個master被sentinel集羣監控時,需要爲它指定一個參數,這個參數指定了當需要判決master爲不可用,並且進行failover時,所需要的sentinel數量,本文中我們暫時稱這個參數爲票數

不過,當failover主備切換真正被觸發後,failover並不會馬上進行,還需要sentinel中的大多數sentinel授權後纔可以進行failover。

當ODOWN時,failover被觸發。failover一旦被觸發,嘗試去進行failover的sentinel會去獲得“大多數”sentinel的授權(如果票數比大多數還要大的時候,則詢問更多的sentinel)

這個區別看起來很微妙,但是很容易理解和使用。例如,集羣中有5個sentinel,票數被設置爲2,當2個sentinel認爲一個master已經不可用了以後,將會觸發failover,但是,進行failover的那個sentinel必須先獲得至少3個sentinel的授權纔可以實行failover。
如果票數被設置爲5,要達到ODOWN狀態,必須所有5個sentinel都主觀認爲master爲不可用,要進行failover,那麼得獲得所有5個sentinel的授權。

方案二 集羣

Redis Cluster提供了一種運行Redis安裝的方法,其中數據 在多個Redis節點之間自動分片。
Redis Cluster還在分區期間提供一定程度的可用性,實際上是在某些節點發生故障或無法通信時繼續運行的能力。但是,如果發生較大的故障(例如,當大多數主設備不可用時),羣集將停止運行。

  • 能夠在多個節點之間自動拆分數據集。
  • 當節點的子集遇到故障或無法與羣集的其餘部分通信時,能夠繼續操作。
    Redis羣集TCP端口
    每個Redis羣集節點都需要打開兩個TCP連接。用於爲客戶端提供服務的普通Redis TCP端口,例如6379,加上通過向數據端口添加10000獲得的端口,因此示例中爲16379。

第二個高端口用於集羣總線,即使用二進制協議的節點到節點通信通道。節點使用集羣總線進行故障檢測,配置更新,故障轉移授權等。客戶端永遠不應嘗試與羣集總線端口通信,但始終使用正常的Redis命令端口,但請確保在防火牆中打開兩個端口,否則Redis羣集節點將無法通信。

命令端口和集羣總線端口偏移是固定的,始終爲10000。

請注意,對於每個節點,要使Redis羣集正常工作,您需要:

  • 用於與客戶端通信的普通客戶端通信端口(通常爲6379)對所有需要訪問羣集的客戶端以及所有其他羣集節點(使用客戶端端口進行密鑰遷移)開放。
  • 必須可以從所有其他羣集節點訪問羣集總線端口(客戶端端口+ 10000)。
  • 如果不打開兩個TCP端口,則羣集將無法按預期工作。

集羣總線使用不同的二進制協議進行節點到節點的數據交換,這更適合於使用很少的帶寬和處理時間在節點之間交換信息。

Redis羣集數據分片

Redis Cluster不使用一致的散列,而是使用不同形式的分片,其中每個鍵在概念上都是我們稱之爲散列槽的一部分。
Redis集羣中有16384個散列槽,爲了計算給定密鑰的散列槽,我們只需採用密鑰模數16384的CRC16。
Redis羣集中的每個節點都負責哈希槽的子集,例如,您可能擁有一個包含3個節點的羣集,其中:

  • 節點A包含從0到5500的散列槽。
  • 節點B包含從5501到11000的散列槽。
  • 節點C包含從11001到16383的散列槽。

這允許輕鬆添加和刪除集羣中的節點。例如,如果我想添加一個新節點D,我需要將一些哈希槽從節點A,B,C移動到D.同樣,如果我想從羣集中刪除節點A,我只需移動A服務的哈希槽。到B和C.當節點A爲空時,我可以完全從集羣中刪除它。

因爲將哈希槽從一個節點移動到另一個節點不需要停止操作,添加和刪除節點,或者更改節點所持有的哈希槽的百分比,所以不需要任何停機時間。

只要涉及單個命令執行(或整個事務或Lua腳本執行)的所有鍵都屬於同一個哈希槽,Redis Cluster就支持多個鍵操作。用戶可以通過使用稱爲哈希標記的概念強制多個密鑰成爲同一哈希槽的一部分。

散列標記記錄在Redis集羣規範中,但要點是如果密鑰中{}括號之間有子字符串,則只對字符串內部的內容進行散列,例如this{foo}key並another{foo}key 保證位於相同的散列槽中,並且可以在具有多個鍵作爲參數的命令中一起使用。

Redis Cluster主從模型

爲了在主節點子集發生故障或無法與大多數節點通信時保持可用,Redis Cluster使用主從模型,其中每個散列槽從1(主機本身)到N個副本(N) -1個額外的從節點)。
在具有節點A,B,C的示例羣集中,如果節點B發生故障,則羣集無法繼續,因爲我們不再能夠在5501-11000範圍內提供服務哈希位置的方法。
然而,當創建集羣時(或稍後),我們向每個主節點添加一個從節點,以便最終集羣由作爲主節點的A,B,C和作爲從節點的A1,B1,C1組成。 ,如果節點B出現故障,系統就能繼續運行。
節點B1複製B,B失敗,集羣將節點B1升級爲新的主節點,並將繼續正常運行。
但請注意,如果節點B和B1同時發生故障,Redis Cluster將無法繼續運行。

Redis羣集一致性保證

Redis Cluster無法保證強一致性。實際上,這意味着在某些條件下,Redis Cluster可能會丟失系統向客戶端確認的寫入。

Redis Cluster可能丟失寫入的第一個原因是它使用異步複製。這意味着在寫入期間會發生以下情況:

  • 您的客戶端寫入主B.
  • 主人B向您的客戶回覆確定。
  • 主設備B將寫入傳播到其從設備B1,B2和B3。

正如你所看到的,B在回覆客戶端之前並沒有等待來自B1,B2,B3的確認,因爲這對Redis來說是一個過高的延遲懲罰,所以如果你的客戶端寫了一些內容,B會確認寫入,但是在崩潰之前崩潰能夠將寫入發送到其從屬,其中一個從屬(沒有接收到寫入)可以被提升爲主,永遠丟失寫入。

這與配置爲每秒將數據刷新到磁盤的大多數數據庫所發生的情況非常相似,因此,由於過去使用不涉及分佈式系統的傳統數據庫系統的經驗,因此您已經能夠推斷這種情況。同樣,您可以通過在回覆客戶端之前強制數據庫刷新磁盤上的數據來提高一致性,但這通常會導致性能過低。在Redis Cluster的情況下,這相當於同步複製。

基本上需要在性能和一致性之間進行權衡。

Redis Cluster在絕對需要時支持同步寫入,通過WAIT命令實現,這使得丟失寫入的可能性大大降低,但請注意,即使使用同步複製,Redis Cluster也不會實現強一致性:在更復雜的情況下總是可以實現失敗場景,無法接收寫入的從站被選爲主站。

還有另一個值得注意的情況是,Redis羣集將丟失寫入,這種情況發生在網絡分區中,其中客戶端與少數實例(至少包括主服務器)隔離。

以6個節點簇爲例,包括A,B,C,A1,B1,C1,3個主站和3個從站。還有一個客戶,我們稱之爲Z1。

在發生分區之後,可能在分區的一側有A,C,A1,B1,C1,在另一側有B和Z1。

Z1仍然可以寫入B,它將接受其寫入。如果分區在很短的時間內恢復,羣集將繼續正常運行。但是,如果分區持續足夠的時間使B1在分區的多數側被提升爲主,則Z1發送給B的寫入將丟失。

請注意,Z1將能夠發送到B的寫入量存在最大窗口:如果分區的多數方面已經有足夠的時間將從屬設備選爲主設備,則少數端的每個主節點都會停止接受寫入。

這段時間是Redis Cluster的一個非常重要的配置指令,稱爲節點超時。

節點超時過後,主節點被視爲失敗,可以由其中一個副本替換。類似地,在節點超時已經過去而主節點無法感知大多數其他主節點之後,它進入錯誤狀態並停止接受寫入。

Redis羣集配置參數

我們即將創建一個示例集羣部署。在繼續之前,讓我們介紹Redis Cluster在redis.conf文件中引入的配置參數。有些人會很明顯,有些人會在你繼續閱讀時更清楚。

  • cluster-enabled<yes/no>:如果是,則在特定Redis實例中啓用Redis羣集支持。否則,實例像往常一樣作爲獨立實例啓動。
  • cluster-config-file:請注意,儘管有此選項的名稱,但這不是用戶可編輯的配置文件,而是每次發生更改時Redis羣集節點自動保持羣集配置(基本上是狀態)的文件,爲了能夠在啓動時重新閱讀它。該文件列出了集羣中其他節點,狀態,持久變量等內容。由於某些消息接收,通常會將此文件重寫並刷新到磁盤上。
  • cluster-node-timeout:Redis羣集節點不可用的最長時間,不會被視爲失敗。如果主節點的可訪問時間超過指定的時間,則其從屬節點將進行故障轉移。此參數控制Redis羣集中的其他重要事項。值得注意的是,在指定時間內無法訪問大多數主節點的每個節點都將停止接受查詢。
  • cluster-slave-validity-factor:如果設置爲零,則從站將始終嘗試對主站進行故障切換,而不管主站和從站之間的鏈路是否保持斷開連接的時間長短。如果該值爲正,則計算最大斷開時間作爲節點超時值乘以此選項提供的因子,如果節點是從屬節點,則如果主鏈接斷開連接的時間超過指定的時間,則不會嘗試啓動故障轉移。例如,如果節點超時設置爲5秒,並且有效性因子設置爲10,則從主設備斷開超過50秒的從設備將不會嘗試故障轉移其主設備。請注意,如果沒有從站能夠對其進行故障轉移,則任何不同於零的值都可能導致Redis羣集在主站發生故障後不可用。在這種情況下,只有當原始主服務器重新加入羣集時,羣集纔會返回。
  • cluster-migration-barrier:主服務器將保持連接的最小從服務器數,以便另一個從服務器遷移到不再由任何從服務器覆蓋的主服務器。有關詳細信息,請參閱本教程中有關副本遷移的相應部分。
    cluster-require-full-coverage<yes/no>:如果設置爲yes,則默認情況下,如果任何節點未覆蓋某個百分比的密鑰空間,則集羣將停止接受寫入。如果該選項設置爲no,即使只能處理有關鍵子集的請求,羣集仍將提供查詢。

創建和使用Redis羣集

要創建集羣,我們首先要做的是在集羣模式下運行一些空的Redis實例。這基本上意味着不使用普通的Redis實例創建集羣,因爲需要配置特殊模式,以便Redis實例啓用集羣特定的功能和命令。

最小的Redis羣集配置文件

port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

正如您所看到的,啓用集羣模式的只是cluster-enabled 指令。每個實例還包含存儲此節點配置的文件路徑,默認情況下爲nodes.conf。它只是在Redis Cluster實例啓動時生成,並在每次需要時更新。

cat nodes-30001.conf
ad7957bb9d7194de7bbb16a915130aed43429ecf :0@0 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0

ad7957bb9d7194de7bbb16a915130aed43429ecf :節點ID 唯一

請注意,按預期工作的最小羣集需要包含至少三個主節點。對於您的第一次測試,強烈建議啓動具有三個主設備和三個從設備的六節點集羣。

爲此,請輸入一個新目錄,並創建以我們將在任何給定目錄中運行的實例的端口號命名的以下目錄

手動
  • 準備

mkdir cluster-test
cd cluster-test
mkdir 7000 7001 7002 7003 7004 7005

cp …/…/redis.conf ./7000
修改配置文件,遵循最小配置單元修改

  • 啓動redis服務

…/src/redis-server ./7000/redis.conf

  • 執行命令 構建集羣

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
–cluster-replicas 1

這裏使用的命令是create,因爲我們想要創建一個新的集羣。該選項–cluster-replicas 1意味着我們希望每個創建的主服務器都有一個從服 其他參數是我要用於創建新集羣的實例的地址列表。

顯然,我們要求的唯一設置是創建一個包含3個主服務器和3個從服務器的集羣。

Redis-cli將爲您提供配置。鍵入yes接受建議的配置。將配置並加入羣集,這意味着實例將被引導爲彼此通信。最後,如果一切順利,你會看到這樣的消息:

[OK] All 16384 slots covered

這意味着至少有一個主實例爲16384個可用插槽提供服務。

自動

如果您不想通過如上所述手動配置和執行單個實例來創建Redis羣集,則可以使用更簡單的系統(但您不會學習相同數量的操作詳細信息)。

只需檢查utils/create-clusterRedis發行版中的目錄即可。create-cluster內部有一個腳本(與其包含的目錄同名),它是一個簡單的bash腳本。要啓動具有3個主服務器和3個從服務器的6節點集羣,只需鍵入以下命令:

create-cluster start
create-cluster create

start:創建redis的實例;create:創建集羣

當redis-cli實用程序希望您接受羣集佈局時,回覆"yes"。

您現在可以與羣集交互,默認情況下,第一個節點將從端口30001開始。完成後,使用以下命令停止羣集:

create-cluster stop。

管理

#查看集羣的節點信息
redis-cli -c -p 30001 cluster nodes

參考文檔: https://redis.io/topics/cluster-tutorial

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章