1. 程式人生 > >Ubuntu 16.04下Redis Cluster集群搭建(官方原始方案)

Ubuntu 16.04下Redis Cluster集群搭建(官方原始方案)

選擇 正數 mil 請求 點數據 包含 最終 util 交互

前提:先安裝好Redis,參考:http://www.cnblogs.com/EasonJim/p/7599941.html

說明:Redis Cluster集群模式可以做到動態增加節點和下線節點,使用起來非常的方便。

下面教程主要是通過官方提供的文檔進行搭建測試:

https://redis.io/topics/cluster-tutorial

http://www.redis.cn/topics/cluster-tutorial.html

http://ifeve.com/redis-cluster-tutorial/

http://ifeve.com/redis-cluster-spec/(翻譯自官方高級使用教程)

上面中文教程都可以在官方提供的文檔中找到。

原理應該如下圖所示:

技術分享

技術分享

註意:以下的搭建教程比較簡單,基於偽集群的模式,如果是生產環境可以每臺機部署一個實例。操作基本一致。

這篇教程是Redis集群的簡要介紹,而非講解分布式系統的復雜概念。它主要從一個使用者的角度介紹如何搭建、測試和使用Redis集群,至於Redis集群的詳細設計將在“Redis集群規範”中進行描述。

本教程以redis使用者的角度,用簡單易懂的方式介紹Redis集群的可用性和一致性。

註意: 本教程要求Redis3.0或以上的版本。

如果你打算部署Redis集群,你可以讀一些關於集群的詳細設計,當然,這不是必須的。由這篇教程入門,先大概使用一下Redis的集群,然後再讀Redis集群的詳細設計,也是不錯的選擇。

Redis集群 101

Redis集群在啟動的時候就自動在多個節點間分好片。同時提供了分片之間的可用性:當一部分redis節點故障或網絡中斷,集群也能繼續工作。但是,當大面積的節點故障或網絡中斷(比如大部分的主節點都不可用了),集群就不能使用。

所以,從實用性的角度,Redis集群提供以下功能:

  • 自動把數據切分到多個Redis節點中
  • 當一部分節點掛了或不可達,集群依然能繼續工作

Redis集群的TCP端口

Redis集群中的每個節點都需要建立2個TCP連接,監聽這2個端口:一個端口稱之為“客戶端端口”,用於接受客戶端指令,與客戶端交互,比如6379;另一個端口稱之為“集群總線端口”,是在客戶端端口號上加10000,比如16379,用於節點之間通過二進制協議通訊。各節點通過集群總線檢測宕機節點、更新配置、故障轉移驗證等。客戶端只能使用客戶端端口,不能使用集群總線端口。請確保你的防火墻允許打開這兩個端口,否則Redis集群沒法工作。客戶端端口和集群總線端口之間的差值是固定的,集群總線端口比客戶端端口高10000。

註意,關於集群的2個端口:

  • 客戶端端口(一般是6379)需要對所有客戶端和集群節點開放,因為集群節點需要通過該端口轉移數據。
  • 集群總線端口(一般是16379)只需對集群中的所有節點開放

這2個端口必須打開,否則集群沒法正常工作。

集群節點之間通過集群總線端口交互數據,使用的協議不同於客戶端的協議,是二進制協議,這可以減少帶寬和處理時間。

Redis集群數據的分片

Redis集群不是使用一致性哈希,而是使用哈希槽。整個Redis集群有16384個哈希槽,決定一個key應該分配到那個槽的算法是:計算該key的CRC16結果再模16834。

集群中的每個節點負責一部分哈希槽,比如集群中有3個節點,則:

  • 節點A存儲的哈希槽範圍是:0 – 5500
  • 節點B存儲的哈希槽範圍是:5501 – 11000
  • 節點C存儲的哈希槽範圍是:11001 – 16384

這樣的分布方式方便節點的添加和刪除。比如,需要新增一個節點D,只需要把A、B、C中的部分哈希槽數據移到D節點。同樣,如果希望在集群中刪除A節點,只需要把A節點的哈希槽的數據移到B和C節點,當A節點的數據全部被移走後,A節點就可以完全從集群中刪除。

因為把哈希槽從一個節點移到另一個節點是不需要停機的,所以,增加或刪除節點,或更改節點上的哈希槽,也是不需要停機的。

如果多個key都屬於一個哈希槽,集群支持通過一個命令(或事務, 或lua腳本)同時操作這些key。通過“哈希標簽”的概念,用戶可以讓多個key分配到同一個哈希槽。哈希標簽在集群詳細文檔中有描述,這裏做個簡單介紹:如果key含有大括號”{}”,則只有大括號中的字符串會參與哈希,比如”this{foo}”和”another{foo}”這2個key會分配到同一個哈希槽,所以可以在一個命令中同時操作他們。

Redis集群的主從模式

為了保證在部分節點故障或網絡不通時集群依然能正常工作,集群使用了主從模型,每個哈希槽有一(主節點)到N個副本(N-1個從節點)。在我們剛才的集群例子中,有A,B,C三個節點,如果B節點故障集群就不能正常工作了,因為B節點中的哈希槽數據沒法操作。但是,如果我們給每一個節點都增加一個從節點,就變成了:A,B,C三個節點是主節點,A1, B1, C1 分別是他們的從節點,當B節點宕機時,我們的集群也能正常運作。B1節點是B節點的副本,如果B節點故障,集群會提升B1為主節點,從而讓集群繼續正常工作。但是,如果B和B1同時故障,集群就不能繼續工作了。

Redis集群的一致性保證

Redis集群不能保證強一致性。一些已經向客戶端確認寫成功的操作,會在某些不確定的情況下丟失。

產生寫操作丟失的第一個原因,是因為主從節點之間使用了異步的方式來同步數據。

一個寫操作是這樣一個流程:

      1)客戶端向主節點B發起寫的操作
      2)主節點B回應客戶端寫操作成功
      3)主節點B向它的從節點B1,B2,B3同步該寫操作

從上面的流程可以看出來,主節點B並沒有等從節點B1,B2,B3寫完之後再回復客戶端這次操作的結果。所以,如果主節點B在通知客戶端寫操作成功之後,但同步給從節點之前,主節點B故障了,其中一個沒有收到該寫操作的從節點會晉升成主節點,該寫操作就這樣永遠丟失了。

就像傳統的數據庫,在不涉及到分布式的情況下,它每秒寫回磁盤。為了提高一致性,可以在寫盤完成之後再回復客戶端,但這樣就要損失性能。這種方式就等於Redis集群使用同步復制的方式。

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

如果真的需要,Redis集群支持同步復制的方式,通過WAIT指令來實現,這可以讓丟失寫操作的可能性降到很低。但就算使用了同步復制的方式,Redis集群依然不是強一致性的,在某些復雜的情況下,比如從節點在與主節點失去連接之後被選為主節點,不一致性還是會發生。

這種不一致性發生的情況是這樣的,當客戶端與少數的節點(至少含有一個主節點)網絡聯通,但他們與其他大多數節點網絡不通。比如6個節點,A,B,C是主節點,A1,B1,C1分別是他們的從節點,一個客戶端稱之為Z1。

當網絡出問題時,他們被分成2組網絡,組內網絡聯通,但2組之間的網絡不通,假設A,C,A1,B1,C1彼此之間是聯通的,另一邊,B和Z1的網絡是聯通的。Z1可以繼續往B發起寫操作,B也接受Z1的寫操作。當網絡恢復時,如果這個時間間隔足夠短,集群仍然能繼續正常工作。如果時間比較長,以致B1在大多數的這邊被選為主節點,那剛才Z1發給B的寫操作都將丟失。

註意,Z1給B發送寫操作是有一個限制的,如果時間長度達到了大多數節點那邊可以選出一個新的主節點時,少數這邊的所有主節點都不接受寫操作。

這個時間的配置,稱之為節點超時(node timeout),對集群來說非常重要,當達到了這個節點超時的時間之後,主節點被認為已經宕機,可以用它的一個從節點來代替。同樣,在節點超時時,如果主節點依然不能聯系到其他主節點,它將進入錯誤狀態,不再接受寫操作。

Redis集群參數配置

我們後面會部署一個Redis集群作為例子,在那之前,先介紹一下集群在redis.conf中的參數。

  • cluster-enabled <yes/no>: 如果配置”yes”則開啟集群功能,此redis實例作為集群的一個節點,否則,它是一個普通的單一的redis實例。
  • cluster-config-file <filename>: 註意:雖然此配置的名字叫“集群配置文件”,但是此配置文件不能人工編輯,它是集群節點自動維護的文件,主要用於記錄集群中有哪些節點、他們的狀態以及一些持久化參數等,方便在重啟時恢復這些狀態。通常是在收到請求之後這個文件就會被更新。
  • cluster-node-timeout <milliseconds>: 這是集群中的節點能夠失聯的最大時間,超過這個時間,該節點就會被認為故障。如果主節點超過這個時間還是不可達,則用它的從節點將啟動故障遷移,升級成主節點。註意,任何一個節點在這個時間之內如果還是沒有連上大部分的主節點,則此節點將停止接收任何請求。
  • cluster-slave-validity-factor <factor>: 如果設置成0,則無論從節點與主節點失聯多久,從節點都會嘗試升級成主節點。如果設置成正數,則cluster-node-timeout乘以cluster-slave-validity-factor得到的時間,是從節點與主節點失聯後,此從節點數據有效的最長時間,超過這個時間,從節點不會啟動故障遷移。假設cluster-node-timeout=5,cluster-slave-validity-factor=10,則如果從節點跟主節點失聯超過50秒,此從節點不能成為主節點。註意,如果此參數配置為非0,將可能出現由於某主節點失聯卻沒有從節點能頂上的情況,從而導致集群不能正常工作,在這種情況下,只有等到原來的主節點重新回歸到集群,集群才恢復運作。
  • cluster-migration-barrier <count>:主節點需要的最小從節點數,只有達到這個數,主節點失敗時,它從節點才會進行遷移。更詳細介紹可以看本教程後面關於副本遷移到部分。
  • cluster-require-full-coverage <yes/no>:在部分key所在的節點不可用時,如果此參數設置為”yes”(默認值), 則整個集群停止接受操作;如果此參數設置為”no”,則集群依然為可達節點上的key提供讀操作。

創建和使用Redis集群

註意:手動部署Redis集群能夠很好的了解它是如何運作的,但如果你希望盡快的讓集群運行起來,可以跳過本節和下一節,直接到”使用create-cluster腳本創建Redis集群”章節。

要創建集群,首先需要以集群模式運行的空redis實例。也就說,以普通模式啟動的redis是不能作為集群的節點的,需要以集群模式啟動的redis實例才能有集群節點的特性、支持集群的指令,成為集群的節點。

下面是最小的redis集群的配置文件(redis.conf):

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

開啟集群模式只需打開cluster-enabled配置項即可。每一個redis實例都包含一個配置文件,默認是nodes.conf(啟動時會自動生成),用於存儲此節點的一些配置信息。這個配置文件由redis集群的節點自行創建和更新,不能由人手動地去修改。

一個最小的集群需要最少3個主節點。第一次測試,強烈建議你配置6個節點:3個主節點和3個從節點。

開始測試,步驟如下:先進入新的目錄,以redis實例的端口為目錄名,創建目錄,我們將在這些目錄裏運行我們的實例。

類似這樣:

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

在7000-7005的每個目錄中創建配置文件redis.conf,內容就用上面的最簡配置做模板,註意修改端口號,改為跟目錄一致的端口。

把你的Redis服務器(用GitHub中的不穩定分支的最新的代碼編譯來/或者穩定代碼)拷貝到cluster-test目錄,然後打開6個終端頁準備測試。

第一臺:

在每個終端啟動一個redis實例,指令類似這樣:

cd 7000
../redis-server ./redis.conf

在日誌中我們可以看到,由於沒有nodes.conf文件不存在,每個節點都給自己一個新的ID。

[82462] 26 Nov 11:56:55.329 * No cluster configuration found, I‘m 97a3a64667477371c4479320d683e4c8db5858b1

這個ID將一直被此節點使用,作為此節點在整個集群中的唯一標識。節點區分其他節點也是通過此ID來標識,而非IP或端口。IP可以改,端口可以改,但此ID不能改,直到這個節點離開集群。這個ID稱之為節點ID(Node ID)。

第二臺:

第三臺:

第四臺:

第五臺:

第六臺:

重復第一臺的操作。

創建集群

現在6個實例已經運行起來了,我們需要給節點寫一些有意義的配置來創建集群。redis集群的命令工具redis-trib可以讓我們創建集群變得非常簡單。redis-trib是一個用ruby寫的腳本,用於給各節點發指令創建集群、檢查集群狀態或給集群重新分片等。redis-trib在Redis源碼的src目錄下,需要gem redis來運行redis-trib。

gem install redis

創建集群只需輸入指令:

./redis-trib.rb create --replicas 1 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

這裏用的命令是create,因為我們需要創建一個新的集群。選項”–replicas 1”表示每個主節點需要一個從節點。其他參數就是需要加入這個集群的Redis實例的地址。

我們創建的集群有3個主節點和3個從節點。

redis-trib會給你一些配置建議,輸入yes表示接受。集群會被配置並彼此連接好,意思是各節點實例被引導彼此通話並最終形成集群。最後,如果一切順利,會看到類似下面的信息:

[OK] All 16384 slots covered

這表示,16384個哈希槽都被主節點正常服務著。

使用create-cluster腳本創建redis集群

如果你不想像上面那樣,單獨的手工配置各節點的方式來創建集群,還有一個更簡單的系統(當然也沒法了解到集群運作的一些細節)。

在utils/create-cluster目錄下,有一個名為create-cluster的bash腳本。如果需要啟動一個有3個主節點和3個從節點的集群,只需要輸入以下指令

#1
create-cluster start #2
create-cluster create

在步驟2,當redis-trib要你接受集群的布局時,輸入”yes”。

現在你可以跟集群交互,第一個節點的起始端口默認是30001。當你完成後,停止集群用如下指令:

create-cluster stop

請查看目錄下的README,它有詳細的介紹如何使用此腳本。

實際操作如下:

版本:4.0.2

下載地址:https://redis.io/download

離線版本:(鏈接: https://pan.baidu.com/s/1bpwDtOr 密碼: 4cxk)

源碼編譯:

wget http://download.redis.io/releases/redis-4.0.2.tar.gz
tar xzf redis-4.0.2.tar.gz
cd redis-4.0.2
make

如果不安裝到指定位置,那麽程序默認放在src文件夾下,

創建集群文件及文件夾:

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

進入7000創建redis.conf,內容如下:

cd 7000
sudo vim redis.conf
#內容
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

進入7001創建redis.conf,內容如下:

cd 7001
sudo vim redis.conf
#內容
port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

進入7002創建redis.conf,內容如下:

cd 7002
sudo vim redis.conf
#內容
port 7002
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

進入7003創建redis.conf,內容如下:

cd 7003
sudo vim redis.conf
#內容
port 7003
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes 

進入7004創建redis.conf,內容如下:

cd 7004
sudo vim redis.conf
#內容
port 7004
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

進入7005創建redis.conf,內容如下:

cd 7005
sudo vim redis.conf
#內容
port 7005
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

分別啟動6臺集群:

cd 7000
../redis-server ./redis.conf
cd 7001
../redis-server ./redis.conf
cd 7002
../redis-server ./redis.conf
cd 7003
../redis-server ./redis.conf
cd 7004
../redis-server ./redis.conf
cd 7005
../redis-server ./redis.conf

創建集群:

先安裝ruby

sudo apt-get ruby

進入src文件夾

再通過gem安裝redis

cd src
gem install redis

如果出現錯誤,參考:http://www.cnblogs.com/EasonJim/p/7629314.html

啟動

./redis-trib.rb create --replicas 1 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

期間會提示輸入yes,然後基本完成。輸出的信息上有提示哪些是主節點和從節點。

參考:

http://ifeve.com/redis-cluster-tutorial/(以上內容部分轉自此篇文章)

http://blog.csdn.net/fengshizty/article/details/51368004 (節點操作的測試)

http://www.redis.cn/topics/cluster-tutorial.html

http://ifeve.com/redis-cluster-spec/

http://os.51cto.com/art/201512/499551.htm

http://blog.csdn.net/robertohuang/article/details/70766809

http://blog.csdn.net/robertohuang/article/details/70768922

http://blog.csdn.net/robertohuang/article/details/70833231

http://blog.chinaunix.net/uid-28396214-id-4981572.html

http://blog.51yip.com/nosql/1725.html

http://www.cnblogs.com/wuxl360/p/5920330.html

http://blog.csdn.net/men_wen/article/details/72853078

http://blog.csdn.net/xu470438000/article/details/42971091

http://www.cnblogs.com/gomysql/p/4395504.html

Ubuntu 16.04下Redis Cluster集群搭建(官方原始方案)