Redis主從複製和集羣配置

Redis主從複製和集羣配置

 

 

 

 

redis主從複製

概述

1、Redis的複製功能是支持多個數據庫之間的數據同步。一類是主數據庫(master)一類是從數據庫(slave),主數據庫可以進行讀寫操作,當發生寫操作的時候自動將數據同步到從數據庫,而從數據庫一般是隻讀的,並接收主數據庫同步過來的數據,一個主數據庫可以有多個從數據庫,而一個從數據庫只能有一個主數據庫。

2、通過redis的複製功能可以很好的實現數據庫的讀寫分離,提高服務器的負載能力。主數據庫主要進行寫操作,而從數據庫負責讀操作。

 

 

主從複製過程

主從複製過程:見下圖

 

 

過程:

1:當一個從數據庫啓動時,會向主數據庫發送sync命令,

2:主數據庫接收到sync命令後會開始在後臺保存快照(執行rdb操作),並將保存期間接收到的命令緩存起來

3:當快照完成後,redis會將快照文件和所有緩存的命令發送給從數據庫。

4:從數據庫收到後,會載入快照文件並執行收到的緩存的命令。

 

注意:redis2.8之前的版本:當主從數據庫同步的時候從數據庫因爲網絡原因斷開重連後會重新執行上述操作,不支持斷點續傳。

redis2.8之後支持斷點續傳。

 

 

配置

 

Redis主從結構支持一主多從

主節點:192.168.33.130

從節點:192.168.33.131

注意:所有從節點的配置都一樣

 


方式1:手動修改配置文件

只需要額外修改從節點中redis的配置文件中的slaveof屬性即可

slaveof 192.168.33.130 6379

配置修改圖示:

 


修改完之後啓動master和slave的redis服務

查看結果:

[root@bogon redis-3.0.7]# src/redis-cli -p 6379
127.0.0.1:6379> info

顯示配置效果圖示:

1、192.168.33.130主機:啓動130主節點上面的redis,查看redis的info信息

 

 

2、192.168.33.131主機:啓動131從節點上面的redis,查看redis的info信息

 

 


方式2:動態設置

通過redis-cli 連接到從節點服務器,執行下面命令即可。

slaveof 192.168.33.130 6379

演示結果和手動方式一致。

 


注意事項

如果你使用主從複製,那麼要確保你的master激活了持久化,或者確保它不會在當掉後自動重啓。原因:

slave是master的完整備份,因此如果master通過一個空數據集重啓,slave也會被清掉。

在配置redis複製功能的時候如果主數據庫設置了密碼,需要在從數據的配置文件中通過masterauth參數設置主數據庫的密碼,這樣從數據庫在連接主數據庫時就會自動使用auth命令認證了。相當於做了一個免密碼登錄。

 

 

 

 

redisSentinel


sentinel功能

redis的sentinel系統用於管理多個redis服務器,該系統主要執行三個任務:監控、提醒、自動故障轉移。

 

1、監控(Monitoring): Redis Sentinel實時監控主服務器和從服務器運行狀態,並且實現自動切換。

2、提醒(Notification):當被監控的某個 Redis 服務器出現問題時, Redis Sentinel 可以向系統管理員發送通知, 也可以通過 API 向其他程序發送通知。

3、自動故障轉移(Automatic failover): 當一個主服務器不能正常工作時,Redis Sentinel 可以將一個從服務器升級爲主服務器, 並對其他從服務器進行配置,讓它們使用新的主服務器。當應用程序連接Redis 服務器時, Redis Sentinel會告之新的主服務器地址和端口。

 

注意:在使用sentinel監控主從節點的時候,從節點需要是使用動態方式配置的,如果直接修改配置文件,後期sentinel實現故障轉移的時候會出問題。

 

 

圖示sentinel

 

 

主觀下線和客觀下線:

1、主觀下線狀態:當一個sentinel認爲一個redis服務連接不上的時候,會給這個服務打個標記爲下線狀態。

2、客觀下線狀態:當多個sentinel認爲一個redids連接不上的時候,則認爲這個redis服務確實下線了。這裏的多個sentinel的個數可以在配置文件中設置。

 

主節點:主觀下線和客觀下線

從節點:主觀下線狀態

 

 

sentinel配置

修改sentinel.conf文件

sentinel monitor mymaster 192.168.33.130 6379 2     #最後一個參數視情況決定





最後一個參數爲需要判定客觀下線所需的主觀下線sentinel個數,這個參數不可以大於sentinel個數。


啓動sentinel

redis-sentinel sentinel.conf


啓動後結果圖示:

 

 

 

sentinel日誌明細說明

http://redisdoc.com/topic/sentinel.html

 

通過訂閱指定的頻道信息,當服務器出現故障得時候通知管理員

客戶端可以將 Sentinel 看作是一個只提供了訂閱功能的 Redis 服務器,你不可以使用 PUBLISH 命令向這個服務器發送信息,但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通過訂閱給定的頻道來獲取相應的事件提醒。

一個頻道能夠接收和這個頻道的名字相同的事件。 比如說, 名爲 +sdown 的頻道就可以接收所有實例進入主觀下線(SDOWN)狀態的事件。

 

 


sentinel的一些命令

info

sentinel的基本狀態信息

 

SENTINEL masters

列出所有被監視的主服務器,以及這些主服務器的當前狀態

 

SENTINEL slaves <master name>

列出給定主服務器的所有從服務器,以及這些從服務器的當前狀態

 

SENTINEL get-master-addr-by-name <master name>

返回給定名字的主服務器的 IP 地址和端口號

SENTINEL reset <pattern>

重置所有名字和給定模式 pattern 相匹配的主服務器。重置操作清除主服務器目前的所有狀態, 包括正在執行中的故障轉移, 並移除目前已經發現和關聯的, 主服務器的所有從服務器和 Sentinel 。

 

SENTINEL failover <master name>

當主服務器失效時, 在不詢問其他 Sentinel 意見的情況下, 強制開始一次自動故障遷移,但是它會給其他sentinel發送一個最新的配置,其他sentinel會根據這個配置進行更新

 

 

 

java操作sentinel

 

代碼示例:

import java.util.HashSet;  
//需要在pom.xml文件中引入jedis依賴  
import redis.clients.jedis.HostAndPort;  
import redis.clients.jedis.Jedis;  
import redis.clients.jedis.JedisPoolConfig;  
import redis.clients.jedis.JedisSentinelPool;  
  
public class SentinelTest {  
  
    public static void main(String[] args) {  
        // 使用HashSet添加多個sentinel  
        HashSet<String> sentinels = new HashSet<String>();  
        // 添加sentinel主機和端口  
        sentinels.add("192.168.33.131:26379");  
  
        // 創建config  
        JedisPoolConfig poolConfig = new JedisPoolConfig();  
        // 控制一個pool最多有多少個狀態爲idle(空閒的)的jedis實例。  
        poolConfig.setMaxIdle(10);  
        // 控制一個pool最多有多少個jedis實例。  
        poolConfig.setMaxTotal(100);  
        // 表示當borrow(引入)一個jedis實例時,最大的等待時間,如果超過等待時間,則直接拋出JedisConnectionException;  
        poolConfig.setMaxWaitMillis(2000);  
        // 在borrow一個jedis實例時,是否提前進行validate操作;如果爲true,則得到的jedis實例均是可用的;  
        poolConfig.setTestOnBorrow(true);  
  
        // 通過Jedis連接池創建一個Sentinel連接池  
        JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels,poolConfig);  
        // 獲取master的主機和端口  
        HostAndPort currentHostMaster = pool.getCurrentHostMaster();  
        System.out.println(currentHostMaster.getHost() + "--"+ currentHostMaster.getPort());  
        // 從Sentinel池中獲取資源  
        Jedis resource = pool.getResource();  
        // 打印資源中key爲name的值  
        System.out.println(resource.get("name"));  
        // 關閉資源  
        resource.close();  
    }  
}


打印結果:

 

 

 

 

 

redis集羣


簡介

redis集羣是一個無中心的分佈式Redis存儲架構,可以在多個節點之間進行數據共享,解決了Redis高可用、可擴展等問題。redis集羣提供了以下兩個好處

1、將數據自動切分(split)到多個節點

2、當集羣中的某一個節點故障時,redis還可以繼續處理客戶端的請求。

 

一個 Redis 集羣包含 16384 個哈希槽(hash slot),數據庫中的每個數據都屬於這16384個哈希槽中的一個。集羣使用公式 CRC16(key) % 16384 來計算鍵 key 屬於哪個槽。集羣中的每一個節點負責處理一部分哈希槽。

 

集羣中的主從複製

集羣中的每個節點都有1個至N個複製品,其中一個爲主節點,其餘的爲從節點,如果主節點下線了,集羣就會把這個主節點的一個從節點設置爲新的主節點,繼續工作。這樣集羣就不會因爲一個主節點的下線而無法正常工作。

 

注意:

1、如果某一個主節點和他所有的從節點都下線的話,redis集羣就會停止工作了。redis集羣不保證數據的強一致性,在特定的情況下,redis集羣會丟失已經被執行過的寫命令

2、使用異步複製(asynchronous replication)是 Redis 集羣可能會丟失寫命令的其中一個原因,有時候由於網絡原因,如果網絡斷開時間太長,redis集羣就會啓用新的主節點,之前發給主節點的數據就會丟失。


 

 

安裝配置

修改配置文件redis.conf

daemonize yes  
port 6379  
cluster-enabled yes  
cluster-config-file nodes.conf  
cluster-node-timeout 5000

 

要讓集羣正常運作至少需要三個主節點

我們這裏就簡單在一臺主機上創建6個redis節點來演示集羣配置,實際生產環境中需要每個節點一臺主機。

 

我們要創建的6個redis節點,其中三個爲主節點,三個爲從節點,對應的redis節點的ip和端口對應關係如下:

192.168.33.130:7000  
192.168.33.130:7001  
192.168.33.130:7002  
192.168.33.130:7003  
192.168.33.130:7004  
192.168.33.130:7005


1、首先我們創建6個以端口爲名稱的文件夾(由於每個redis節點啓動的時候,都會在當前文件夾下創建快照文件,所以我們需要創建每個節點的啓動目錄)

mkdir 7000  
mkdir 7001  
mkdir 7002  
mkdir 7003  
mkdir 7004  
mkdir 7005


 

2、接下來把每個節點啓動所需要的配置文件拷貝到相應的啓動目錄:

cp redis.conf  7000  
cp redis.conf  7001  
cp redis.conf  7002  
cp redis.conf  7003  
cp redis.conf  7004  
cp redis.conf  7005



3、然後我們進入每個啓動目錄,修改之前拷貝的redis.conf文件中的端口port 爲上面列出的對應端口。

最終每個節點的配置類似於:

daemonize yes  
port 6379     #只有端口不同,其他相同  
cluster-enabled yes  
cluster-config-file nodes.conf  
cluster-node-timeout 5000

 

4、進入每個啓動目錄,以每個目錄下的redis.conf文件啓動

 

 

使用命令查看redis節點是否啓動

ps -ef | grep redis




5、創建集羣命令

redis-trib.rb  create --replicas 1 192.168.33.130:7000 192.168.33.130:7001 192.168.33.130:7002 192.168.33.130:7003 192.168.33.130:7004 192.168.33.130:7005



  1.  


注意:

5.1、執行上面的命令的時候可能會報錯,因爲是執行的ruby的腳本,需要ruby的環境

錯誤內容:

 

所以我們需要安裝ruby的環境,這裏推薦使用yum安裝:

yum install ruby

5.2、安裝ruby後,執行命令可能還會報錯,提示缺少rubygems組件,使用yum安裝

 

解決方法:

yum install rubygems


5.3、上面兩個步驟後,執行創建集羣目錄可能還會報錯,提示不能加載redis,是因爲缺少redis和ruby的接口,使用gem 安裝。

 

解決方法:

gem install redis


上面三個問題解決後,啓動創建集羣應該可以正常啓動了:

 


這裏輸入yes

 

最後結果:

 

 

到此,我們的集羣搭建成功了。

 

6、接下來我們使用命令進入集羣環境

redis-cli -c -p 7000



redis集羣操作

使用redis-cli客戶端來操作redis集羣,使用命令 :

  1. redis-cli -c -p [port]  



查看集羣中的所有主節點信息

  1. redis-cli -c -p 7000 cluster nodes [| grep master]  





redis集羣添加節點

 

根據添加節點類型的不同,有兩種方法來添加新節點

1、主節點:如果添加的是主節點,那麼我們需要創建一個空節點,然後將某些哈希槽移動到這個空節點裏面

2、從節點:如果添加的是從節點,我們也需要創建一個空節點,然後把這個新節點設置成集羣中某個主節點的複製品。

 

 添加節點:

1、首先把需要添加的節點啓動

創建7006目錄,拷貝7000中的redis.conf到7006中,然後修改端口port爲7006,修改好後進入7006目錄啓動這個節點:

  1. redis-server redis.conf  


2、執行以下命令,將這個新節點添加到集羣中:

  1. redis-trib.rb add-node 192.168.33.130:7006 192.168.33.130:7000  

結果圖示:

 

 

3、執行命令查看剛纔新增的節點:

  1. redis-cli -c -p 7000 cluster nodes  



 

4、增加了新的節點之後,這個新的節點可以成爲主節點或者是從節點

 

4.1將這個新增節點變成從節點


前面我們已經把這個新節點添加到集羣中了,現在我們要讓新節點成爲192.168.33.130:7001的從節點,只需要執行下面的命令就可以了,命令後面的節點ID就是192.168.33.130:7001的節點ID。(注意,這個從節點哈希槽必須爲空,如果不爲空,則需要轉移掉哈希槽使之爲空)

redis-cli -c -p 7006 cluster replicate a246963893faf03c45cc19ef4188f82f5393bfef

 



使用下面命令來確認一下192.168.33.130:7006是否已經成爲192.168.33.130:7001的從節點。

redis-cli -p 7000 cluster nodes | grep slave | grep a246963893faf03c45cc19ef4188f82f5393bfef



 

4.2、將這個新增節點變成主節點:

使用redis-trib程序,將集羣中的某些哈希槽移動到新節點裏面,這個新節點就成爲真正的主節點了。執行下面的命令對集羣中的哈希槽進行移動:

redis-trib.rb reshard 192.168.33.130:7000

命令執行後,系統會提示我們要移動多少哈希槽,這裏移動1000個

 

 

然後還需要指定把這些哈希槽轉移到哪個節點上

 

輸入我們剛纔新增的節點的ID

d113e0f033c98e2f6b88fb93e6e98866256d85c4

 

然後需要我們指定轉移哪幾個幾點的哈希槽

 

輸入all 表示從所有的主節點中隨機轉移,湊夠1000個哈希槽

 

然後再輸入yes,redis集羣就開始分配哈希槽了。

 

 

至此,一個新的主節點就添加完成了,執行命令查看現在的集羣中節點的狀態

  1. redis-cli -c -p 7000 cluster nodes  

結果圖示:

 

 

 

 

Redis集羣刪除節點

 

1、如果刪除的節點是主節點,這裏我們刪除192.168.33.130:7006節點,這個節點有1000個哈希槽

首先要把節點中的哈希槽轉移到其他節點中,執行下面的命令:

  1. redis-trib.rb reshard 192.168.33.130:7000  


系統會提示我們要移動多少哈希槽,這裏移動1000個,因爲192.168.33.130:7006節點有1000個哈希槽。

 

 

然後系統提示我們輸入要接收這些哈希槽的節點的ID,這裏使用192.168.33.130:7001的節點ID

 

 

然後要我們選擇從那些節點中轉出哈希槽,這裏一定要輸入192.168.33.130:7006這個節點的ID

 

最後輸入done表示輸入完畢。

 

最後一步,使用下面的命令把這個節點刪除

redis-trib.rb del-node 192.168.33.130:7000 d113e0f033c98e2f6b88fb93e6e98866256d85c4  //最後一個參數爲需要刪除的節點ID


 


2、如果是從節點,直接刪除即可。

redis-trib.rb del-node 192.168.33.130:7000 d113e0f033c98e2f6b88fb93e6e98866256d85c4   //最後一個參數爲需要刪除節點的ID



 

 

java操作redis集羣

 

向Redis集羣中存入鍵值:

 

 

代碼示例:

import java.util.HashSet;  
//需要再pom.xml中引入jedis依賴  
import redis.clients.jedis.HostAndPort;  
import redis.clients.jedis.JedisCluster;  
import redis.clients.jedis.JedisPool;  
import redis.clients.jedis.JedisPoolConfig;  
  
public class RedisCluster {  
    public static void main(String[] args) {  
        //初始化集合,用於裝下面的多個主機和端口  
        HashSet<HostAndPort> nodes = new HashSet<HostAndPort>();  
          
        //創建多個主機和端口實例  
        HostAndPort hostAndPort = new HostAndPort("192.168.33.130", 7000);  
        HostAndPort hostAndPort1 = new HostAndPort("192.168.33.130", 7001);  
        HostAndPort hostAndPort2 = new HostAndPort("192.168.33.130", 7002);  
        HostAndPort hostAndPort3 = new HostAndPort("192.168.33.130", 7003);  
        HostAndPort hostAndPort4 = new HostAndPort("192.168.33.130", 7004);  
        HostAndPort hostAndPort5 = new HostAndPort("192.168.33.130", 7005);  
          
        //添加多個主機和端口到集合中  
        nodes.add(hostAndPort);  
        nodes.add(hostAndPort1);  
        nodes.add(hostAndPort2);  
        nodes.add(hostAndPort3);  
        nodes.add(hostAndPort4);  
        nodes.add(hostAndPort5);  
          
        //創建config  
        JedisPoolConfig poolConfig = new JedisPoolConfig();  
        //通過config創建集羣實例  
        JedisCluster jedisCluster = new JedisCluster(nodes,poolConfig);  
        //獲取集羣中的key爲name鍵的值  
        String str = jedisCluster.get("name");  
        System.out.println(str);  
    }  
}



打印結果:


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