Redis集羣

1. 安裝Redis3.0

yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc-c++ libstdc++-devel tcl

 

mkdir -p /usr/local/src/redis

cd /usr/local/src/redis

wget http://download.redis.io/releases/redis-3.0.2.tar.gz  或者 rz 上傳

tar -xvf redis-3.0.2.tar.gz

cd redis-3.0.2

make

make test #這個就不要執行了,需要很長時間

make install

 

cp redis.conf /etc/

vi /etc/redis.conf

# 修改如下,默認爲no

daemonize yes

 

#啓動

redis-server /etc/redis.conf

#測試

redis-cli

 

2. 主從複製(讀寫分離)

主從複製的好處有2點:

1、 避免redis單點故障

2、 構建讀寫分離架構,滿足讀多寫少的應用場景

2.1. 主從架構


2.1.1. 啓動實例

創建637963806381目錄,分別將安裝目錄下的redis.conf拷貝到這三個目錄下


 

分別進入這三個目錄,分別修改配置文件,將端口分別設置爲:6379Master)、6380Slave)、6381Slave)。同時要設置pidfile文件爲不同的路徑

 

分別啓動三個redis實例


2.1.2. 設置主從

redis中設置主從有2種方式:

 

1、 在redis.conf中設置slaveof

a) slaveof <masterip> <masterport>

2、 使用redis-cli客戶端連接到redis服務,執行slaveof命令

a) slaveof <masterip> <masterport>

 

第二種方式在重啓後將失去主從複製關係。

 

查看主從信息:INFO replication

 

主:

role:角色

connected_slaves:從庫數量

slave0:從庫信息

 

從:


2.1.3. 測試

在主庫寫入數據:


在從庫讀取數據:


2.2. 主從從架構


2.2.1. 啓動實例


設置主從:


設置從從:


2.2.2. 測試

在主庫設置數據:


6380獲取數據:


在6381獲取數據:


2.3. 從庫只讀

默認情況下redis數據庫充當slave角色時是隻讀的不能進行寫操作


可以在配置文件中開啓非只讀:slave-read-only no

2.4. 複製的過程原理

1、 當從庫和主庫建立MS關係後,會向主數據庫發送SYNC命令;

2、 主庫接收到SYNC命令後會開始在後臺保存快照RDB持久化過程),並將期間接收到的寫命令緩存起來;

3、 當快照完成後,主Redis會將快照文件和所有緩存的寫命令發送給從Redis

4、 從Redis接收到後,會載入快照文件並且執行收到的緩存的命令;

5、 之後,主Redis每當接收到寫命令時就會將命令發送從Redis,從而保證數據的一致;

2.5. 無磁盤複製

通過前面的複製過程我們瞭解到,主庫接收到SYNC的命令時會執行RDB過程,即使在配置文件中禁用RDB持久化也會生成,那麼如果主庫所在的服務器磁盤IO性能較差,那麼這個複製過程就會出現瓶頸,慶幸的是,Redis2.8.18版本開始實現了無磁盤複製功能(不過該功能還是處於試驗階段)。

 

原理:

Redis在與從數據庫進行復制初始化時將不會將快照存儲到磁盤,而是直接通過網絡發送給從數據庫,避免了IO性能差問題

 

開啓無磁盤複製:repl-diskless-sync yes

 

2.6. 複製架構中出現宕機情況,怎麼辦?

如果在主從複製架構中出現宕機的情況,需要分情況看:

1、 從Redis宕機

a) 這個相對而言比較簡單,在Redis中從庫重新啓動後會自動加入到主從架構中,自動完成同步數據;

b) 問題? 如果從庫在斷開期間,主庫的變化不大,從庫再次啓動後,主庫依然會將所有的數據做RDB操作嗎?還是增量更新?(從庫有做持久化的前提下)

i. 不會的,因爲在Redis2.8版本後就實現了,主從斷線後恢復的情況下實現增量複製。

2、 主Redis宕機

a) 這個相對而言就會複雜一些,需要以下2步才能完成

i. 第一步,在從數據庫中執行SLAVEOF NO ONE命令,斷開主從關係並且提升爲主庫繼續服務;

ii. 第二步,將主庫重新啓動後,執行SLAVEOF命令,將其設置爲其他庫的從庫,這時數據就能更新回來;

b) 這個手動完成恢復的過程其實是比較麻煩的並且容易出錯,有沒有好辦法解決呢?當前有的,Redis提高的哨兵sentinel的功能。

 

3. 哨兵(sentinel

3.1. 什麼是哨兵

顧名思義,哨兵的作用就是對Redis的系統的運行情況的監控,它是一個獨立進程。它的功能有2個:

 

1、 監控主數據庫和從數據庫是否運行正常;

2、 主數據出現故障後自動將從數據庫轉化爲主數據庫;

3.2. 原理

單個哨兵的架構:


多個哨兵的架構:


多個哨兵,不僅同時監控主從數據庫,而且哨兵之間互爲監控。

3.3. 環境

當前處於一主多從的環境中:


3.4. 配置哨兵

啓動哨兵進程首先需要創建哨兵配置文件:

 

vim sentinel.conf

輸入內容:

sentinel monitor taotaoMaster 127.0.0.1 6379 1

 

說明:

taotaoMaster:監控主數據的名稱,自定義即可,可以使用大小寫字母和“.-_”符號

127.0.0.1:監控的主數據庫的IP

6379:監控的主數據庫的端口

1:最低通過票數

 

啓動哨兵進程:

redis-sentinel ./sentinel.conf


由上圖可以看到:

1、 哨兵已經啓動,它的id9059917216012421e8e89a4aa02f15b75346d2b7

2、 爲master數據庫添加了一個監控

3、 發現了2slave(由此可以看出,哨兵無需配置slave,只需要指定master,哨兵會自動發現slave

3.5. 從數據庫宕機


 

kill2826進程後,30秒後哨兵的控制檯輸出:

 

2989:X 05 Jun 20:09:33.509 # +sdown slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379

 

說明已經監控到slave宕機了,那麼,如果我們將3380端口的redis實例啓動後,會自動加入到主從複製嗎?


2989:X 05 Jun 20:13:22.716 * +reboot slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379

2989:X 05 Jun 20:13:22.788 # -sdown slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379

 

可以看出,slave從新加入到了主從複製中。-sdown:說明是恢復服務。


3.6. 主庫宕機

哨兵控制檯打印出如下信息:

 

2989:X 05 Jun 20:16:50.300 # +sdown master taotaoMaster 127.0.0.1 6379  說明master服務已經宕機

2989:X 05 Jun 20:16:50.300 # +odown master taotaoMaster 127.0.0.1 6379 #quorum 1/1  

2989:X 05 Jun 20:16:50.300 # +new-epoch 1

2989:X 05 Jun 20:16:50.300 # +try-failover master taotaoMaster 127.0.0.1 6379  開始恢復故障

2989:X 05 Jun 20:16:50.304 # +vote-for-leader 9059917216012421e8e89a4aa02f15b75346d2b7 1  投票選舉哨兵leader現在就一個哨兵所以leader就自己

2989:X 05 Jun 20:16:50.304 # +elected-leader master taotaoMaster 127.0.0.1 6379  選中leader

2989:X 05 Jun 20:16:50.304 # +failover-state-select-slave master taotaoMaster 127.0.0.1 6379 選中其中的一個slave當做master

2989:X 05 Jun 20:16:50.357 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster 127.0.0.1 6379  選中6381

2989:X 05 Jun 20:16:50.357 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster 127.0.0.1 6379  發送slaveof no one命令

2989:X 05 Jun 20:16:50.420 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster 127.0.0.1 6379   等待升級master

2989:X 05 Jun 20:16:50.515 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster 127.0.0.1 6379  升級6381master

2989:X 05 Jun 20:16:50.515 # +failover-state-reconf-slaves master taotaoMaster 127.0.0.1 6379

2989:X 05 Jun 20:16:50.566 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379

2989:X 05 Jun 20:16:51.333 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379

2989:X 05 Jun 20:16:52.382 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379

2989:X 05 Jun 20:16:52.438 # +failover-end master taotaoMaster 127.0.0.1 6379 故障恢復完成

2989:X 05 Jun 20:16:52.438 # +switch-master taotaoMaster 127.0.0.1 6379 127.0.0.1 6381  主數據庫從6379轉變爲6381

2989:X 05 Jun 20:16:52.438 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6381  添加63806381的從庫

2989:X 05 Jun 20:16:52.438 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster 127.0.0.1 6381  添加63796381的從庫

2989:X 05 Jun 20:17:22.463 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster 127.0.0.1 6381 發現6379已經宕機,等待6379的恢復

 


可以看出,目前,6381master,擁有一個slave6380.

 

接下來,我們恢復6379查看狀態:

2989:X 05 Jun 20:35:32.172 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster 127.0.0.1 6381  6379已經恢復服務

2989:X 05 Jun 20:35:42.137 * +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster 127.0.0.1 6381  6379設置爲6381slave


3.7 配置多個哨兵

vim sentinel.conf

輸入內容:

sentinel monitor taotaoMaster 127.0.0.1 6381 2

sentinel monitor taotaoMaster2 127.0.0.1 6381 1

 

3451:X 05 Jun 21:05:56.083 # +sdown master taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:56.083 # +odown master taotaoMaster2 127.0.0.1 6381 #quorum 1/1

3451:X 05 Jun 21:05:56.083 # +new-epoch 1

3451:X 05 Jun 21:05:56.083 # +try-failover master taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:56.086 # +vote-for-leader 3f020a35c9878a12d2b44904f570dc0d4015c2ba 1

3451:X 05 Jun 21:05:56.086 # +elected-leader master taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:56.086 # +failover-state-select-slave master taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:56.087 # +sdown master taotaoMaster 127.0.0.1 6381

3451:X 05 Jun 21:05:56.189 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:56.189 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:56.252 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:57.145 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:57.145 # +failover-state-reconf-slaves master taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:57.234 * +slave-reconf-sent slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:58.149 * +slave-reconf-inprog slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:58.149 * +slave-reconf-done slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:58.203 # +failover-end master taotaoMaster2 127.0.0.1 6381

3451:X 05 Jun 21:05:58.203 # +switch-master taotaoMaster2 127.0.0.1 6381 127.0.0.1 6380

3451:X 05 Jun 21:05:58.203 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster2 127.0.0.1 6380

3451:X 05 Jun 21:05:58.203 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster2 127.0.0.1 6380

4. 集羣

即使有了主從複製,每個數據庫都要保存整個集羣中的所有數據,容易形成木桶效應。

 

使用Jedis實現了分片集羣,是由客戶端控制哪些key數據保存到哪個數據庫中,如果在水平擴容時就必須手動進行數據遷移,而且需要將整個集羣停止服務,這樣做非常不好的。

 

Redis3.0版本的一大特性就是集羣Cluster),接下來我們一起學習集羣。

4.1. 架構


(1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.

(2)節點的fail是通過集羣中超過半數的節點檢測失效時才生效.

(3)客戶端與redis節點直連,不需要中間proxy.客戶端不需要連接集羣所有節點,連接集羣中任何一個可用節點即可

(4)redis-cluster把所有的物理節點映射到[0-16383]slot(插槽),cluster 負責維護node<->slot<->value

4.2. 修改配置文件

1、 設置不同的端口,637963806381

2、 開啓集羣,cluster-enabled yes

3、 指定集羣的配置文件,cluster-config-file "nodes-xxxx.conf"


4.3. 創建集羣

4.3.1. 安裝ruby環境

因爲redis-trib.rb是有ruby語言編寫的所以需要安裝ruby環境

 

yum -y install zlib ruby rubygems

gem install redis

 

手動安裝:

rz上傳redis-3.2.1.gem

gem install -l redis-3.2.1.gem

4.3.2. 創建集羣

首先,進入redis的安裝包路徑下

cd /usr/local/src/redis/redis-3.0.1/src/


執行命令:

./redis-trib.rb create --replicas 0 192.168.56.102:6379 192.168.56.102:6380 192.168.56.102:6381

 

--replicas 0:指定了從數據的數量爲0

 

注意這裏不能使用127.0.0.1,否則在Jedis客戶端使用時無法連接到!

 

redis-trib用法


4.3.3. 測試


 

什麼情況??(error) MOVED 7638 127.0.0.1:6380  

 

因爲abchash槽信息是在6380上,現在使用redis-cli連接的6379,無法完成set操作,需要客戶端跟蹤重定向。

 

redis-cli -c


看到由6379跳轉到了6380,然後再進入6379看能否get到數據


還是被重定向到了6380,不過已經可以獲取到數據了。

4.4. 使用Jedis連接到集羣

添加依賴,要注意jedis的版本爲2.7.2



說明:這裏的jc不需要關閉,因爲內部已經關閉連接了。

4.5. 插槽的分配

通過cluster nodes命令可以查看當前集羣的信息


該信息反映出了集羣中的每個節點的id、身份、連接數、插槽數等。

 

當我們執行set abc 123命令時,redis是如何將數據保存到集羣中的呢?執行步驟:

1、 接收命令set abc 123

2、 通過keyabc)計算出插槽值,然後根據插槽值找到對應的節點。(abc的插槽值爲:7638)

3、 重定向到該節點執行命令

 

整個Redis提供了16384個插槽,也就是說集羣中的每個節點分得的插槽數總和爲16384

./redis-trib.rb 腳本實現了是將16384個插槽平均分配給了N個節點。

 

注意如果插槽數有部分是沒有指定到節點的那麼這部分插槽所對應的key將不能使用

4.6. 插槽和key的關係

計算key的插槽值:

key有效部分使用CRC16算法計算出哈希值,再將哈希值對16384取餘,得到插槽值。

 

什麼是有效部分?

1、 如果key中包含了{符號,且在{符號後存在}符號,並且{}之間至少有一個字符,則有效部分是指{}之間的部分;

a) key={hello}_tatao的有效部分是hello

2、 如果不滿足上一條情況,整個key都是有效部分

a) key=hello_taotao的有效部分是全部

4.7. 新增集羣節點

再開啓一個實例的端口爲6382


執行腳本:

./redis-trib.rb add-node 192.168.56.102:6382 192.168.56.102:6379


已經添加成功!查看集羣信息:


發現沒有插槽數。

 

接下來需要給6382這個服務分配插槽,將6379的一部分(1000個)插槽分配給6382


查看節點情況:


4.8. 刪除集羣節點

想要刪除集羣節點中的某一個節點,需要嚴格執行2步:

1、 將這個節點上的所有插槽轉移到其他節點上;

a) 假設我們想要刪除6380這個節點

b) 執行腳本:./redis-trib.rb reshard 192.168.56.102:6380

c)選擇需要轉移的插槽的數量,因爲33805128,所以轉移5128


d) 輸入轉移的節點的id,我們轉移到6382節點:82ed0d63cfa6d19956dca833930977a87d6ddf7

e) 輸入插槽來源id,也就是6380id

f)輸入done,開始轉移


g)查看集羣信息,可以看到6380節點已經沒有插槽了。


2、 使用redis-trib.rb刪除節點

a) ./redis-trib.rb del-node 192.168.56.102:6380 4a9b8886ba5261e82597f5590fcdb49ea47c4c6c

b) del-node host:port node_id


查看集羣信息,可以看到已經沒有6380這個節點了。


4.9. 故障轉移

如果集羣中的某一節點宕機會出現什麼狀況?我們這裏假設6381宕機。


我們嘗試連接下集羣,並且查看集羣信息,發現6381的節點斷開連接:


我們嘗試執行set命令,結果發現無法執行:


什麼情況?集羣不可用了?? 這集羣也太弱了吧??

4.9.1. 故障機制

1、 集羣中的每個節點都會定期的向其它節點發送PING命令,並且通過有沒有收到回覆判斷目標節點是否下線;

2、 集羣中每一秒就會隨機選擇5個節點,然後選擇其中最久沒有響應的節點放PING命令;

3、 如果一定時間內目標節點都沒有響應,那麼該節點就認爲目標節點疑似下線

4、 當集羣中的節點超過半數認爲該目標節點疑似下線,那麼該節點就會被標記爲下線

5、 當集羣中的任何一個節點下線就會導致插槽區有空檔不完整那麼該集羣將不可用

6、 如何解決上述問題?

a) 在Redis集羣中可以使用主從模式實現某一個節點的高可用

b) 當該節點(master)宕機後,集羣會將該節點的從數據庫(slave)轉變爲(master)繼續完成集羣服務;

4.9.2. 集羣中的主從複製架構

架構:


出現故障:


4.9.3. 創建主從集羣

需要啓動6redis實例,分別是:

6379(主) 6479(從)

6380(主) 6480(從)

6381(主) 6481(從)


啓動redis實例

cd 6379/ && redis-server ./redis.conf && cd ..

cd 6380/ && redis-server ./redis.conf && cd ..

cd 6381/ && redis-server ./redis.conf && cd ..

cd 6479/ && redis-server ./redis.conf && cd ..

cd 6480/ && redis-server ./redis.conf && cd ..

cd 6481/ && redis-server ./redis.conf && cd ..


 

創建集羣,指定了從庫數量爲1,創建順序爲主庫(3個)、從庫(3個):

./redis-trib.rb create --replicas 1 192.168.56.102:6379 192.168.56.102:6380 192.168.56.102:6381 192.168.56.102:6479 192.168.56.102:6480 192.168.56.102:6481


創建成功!查看集羣信息:


4.9.4. 測試


保存、讀取數據OK

 

查看下6480的從庫數據:


看到從6480查看數據也是被重定向到6380.

 

說明集羣一切運行OK

4.9.5. 測試集羣中slave節點宕機

我們將6480節點kill掉,查看情況。


 

查看集羣情況:


發現6480節點不可用。

 

那麼整個集羣可用嗎?


發現集羣可用,可見從數據庫宕機不會影響集羣正常服務

 

恢復6480服務:


測試6480中的數據:


看到已經更新成最新數據。

4.9.6. 測試集羣中master宕機

假設6381宕機:


查看集羣情況:


發現:

16381節點失效不可用

26481節點從slave轉換爲master

 

測試集羣是否可用:


集羣可用。

 

恢復6381


發現:

16381節點可用

26481依然是主節點

36381成爲6481的從數據庫

4.10. 使用集羣需要注意的事項

1、 多鍵的命令操作(如MGETMSET),如果每個鍵都位於同一個節點,則可以正常支持,否則會提示錯誤。

2、 集羣中的節點只能使用0號數據庫,如果執行SELECT切換數據庫會提示錯誤。

 



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