1. 程式人生 > >Redis主從復制和集群配置

Redis主從復制和集群配置

get 行數據 pattern 額外 監控 redis-cli 客戶端 輸入a stat

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屬性即可

[python] view plain copy
  1. slaveof 192.168.33.130 6379

配置修改圖示:

技術分享

配置效果圖示:

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命令認證了。相當於做了一個免密碼登錄。

redis的Sentinel

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文件

[python] view plain copy
  1. sentinel monitor mymaster 192.168.33.130 6379 2 #最後一個參數視情況決定

技術分享

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

啟動sentinel

[python] view plain copy
  1. redis-sentinel sentinel.conf

啟動後結果圖示:

技術分享

sentinel日誌明細說明

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

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

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

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

sentinel的一些命令

[python] view plain copy
  1. INFO

sentinel的基本狀態信息

[python] view plain copy
  1. SENTINEL masters

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

[python] view plain copy
  1. SENTINEL slaves <master name>

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

[python] view plain copy
  1. SENTINEL get-master-addr-by-name <master name>

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

[python] view plain copy
  1. SENTINEL reset <pattern>

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

[python] view plain copy
  1. SENTINEL failover <master name>

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

java操作sentinel

代碼示例:

[java] view plain copy
  1. import java.util.HashSet;
  2. //需要在pom.xml文件中引入jedis依賴
  3. import redis.clients.jedis.HostAndPort;
  4. import redis.clients.jedis.Jedis;
  5. import redis.clients.jedis.JedisPoolConfig;
  6. import redis.clients.jedis.JedisSentinelPool;
  7. public class SentinelTest {
  8. public static void main(String[] args) {
  9. // 使用HashSet添加多個sentinel
  10. HashSet<String> sentinels = new HashSet<String>();
  11. // 添加sentinel主機和端口
  12. sentinels.add("192.168.33.131:26379");
  13. // 創建config
  14. JedisPoolConfig poolConfig = new JedisPoolConfig();
  15. // 控制一個pool最多有多少個狀態為idle(空閑的)的jedis實例。
  16. poolConfig.setMaxIdle(10);
  17. // 控制一個pool最多有多少個jedis實例。
  18. poolConfig.setMaxTotal(100);
  19. // 表示當borrow(引入)一個jedis實例時,最大的等待時間,如果超過等待時間,則直接拋出JedisConnectionException;
  20. poolConfig.setMaxWaitMillis(2000);
  21. // 在borrow一個jedis實例時,是否提前進行validate操作;如果為true,則得到的jedis實例均是可用的;
  22. poolConfig.setTestOnBorrow(true);
  23. // 通過Jedis連接池創建一個Sentinel連接池
  24. JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels,poolConfig);
  25. // 獲取master的主機和端口
  26. HostAndPort currentHostMaster = pool.getCurrentHostMaster();
  27. System.out.println(currentHostMaster.getHost() + "--"+ currentHostMaster.getPort());
  28. // 從Sentinel池中獲取資源
  29. Jedis resource = pool.getResource();
  30. // 打印資源中key為name的值
  31. System.out.println(resource.get("name"));
  32. // 關閉資源
  33. resource.close();
  34. }
  35. }

打印結果:

技術分享

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

[python] view plain copy
  1. daemonize yes
  2. port 6379
  3. cluster-enabled yes
  4. cluster-config-file nodes.conf
  5. cluster-node-timeout 5000

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

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

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

[python] view plain copy
  1. 192.168.33.130:7000
  2. 192.168.33.130:7001
  3. 192.168.33.130:7002
  4. 192.168.33.130:7003
  5. 192.168.33.130:7004
  6. 192.168.33.130:7005



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

[python] view plain copy
  1. mkdir 7000
  2. mkdir 7001
  3. mkdir 7002
  4. mkdir 7003
  5. mkdir 7004
  6. mkdir 7005

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

[python] view plain copy
  1. cp redis.conf 7000
  2. cp redis.conf 7001
  3. cp redis.conf 7002
  4. cp redis.conf 7003
  5. cp redis.conf 7004
  6. cp redis.conf 7005

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

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

[python] view plain copy
  1. daemonize yes
  2. port 6379 #只有端口不同,其他相同
  3. cluster-enabled yes
  4. cluster-config-file nodes.conf
  5. cluster-node-timeout 5000

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

技術分享

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

[python] view plain copy
  1. ps -ef | grep redis

技術分享

5、創建集群命令

[python] view plain copy
  1. 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

註意:

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

錯誤內容:

技術分享

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

[python] view plain copy
  1. yum install ruby

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

技術分享

解決方法:

[python] view plain copy
  1. yum install rubygems

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

技術分享

解決方法:

[python] view plain copy
  1. gem install redis

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

技術分享

技術分享

這裏輸入yes

最後結果:

技術分享

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

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

[python] view plain copy
  1. redis-cli -c -p 7000

redis集群操作

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

[python] view plain copy
  1. redis-cli -c -p [port]

技術分享

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

[python] view plain copy
  1. redis-cli -c -p 7000 cluster nodes [| grep master]

技術分享

redis集群添加節點

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

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

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

添加節點:

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

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

[python] view plain copy
  1. redis-server redis.conf

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

[python] view plain copy
  1. redis-trib.rb add-node 192.168.33.130:7006 192.168.33.130:7000

結果圖示:

技術分享

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

[python] view plain copy
  1. redis-cli -c -p 7000 cluster nodes

技術分享

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

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

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

[python] view plain copy
  1. redis-cli -c -p 7006 cluster replicate a246963893faf03c45cc19ef4188f82f5393bfef

技術分享

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

[python] view plain copy
  1. redis-cli -p 7000 cluster nodes | grep slave | grep a246963893faf03c45cc19ef4188f82f5393bfef

技術分享

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

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

[python] view plain copy
  1. redis-trib.rb reshard 192.168.33.130:7000

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

技術分享

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

技術分享

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

d113e0f033c98e2f6b88fb93e6e98866256d85c4

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

技術分享

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

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

技術分享

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

[python] view plain copy
  1. redis-cli -c -p 7000 cluster nodes

結果圖示:

技術分享

Redis集群刪除節點

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

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

[python] view plain copy
  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表示輸入完畢。

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

[python] view plain copy
  1. redis-trib.rb del-node 192.168.33.130:7000 d113e0f033c98e2f6b88fb93e6e98866256d85c4 //最後一個參數為需要刪除的節點ID

技術分享

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

[python] view plain copy
  1. redis-trib.rb del-node 192.168.33.130:7000 d113e0f033c98e2f6b88fb93e6e98866256d85c4 //最後一個參數為需要刪除節點的ID

技術分享

java操作redis集群

向Redis集群中存入鍵值:

技術分享

代碼示例:

[java] view plain copy
  1. import java.util.HashSet;
  2. //需要再pom.xml中引入jedis依賴
  3. import redis.clients.jedis.HostAndPort;
  4. import redis.clients.jedis.JedisCluster;
  5. import redis.clients.jedis.JedisPool;
  6. import redis.clients.jedis.JedisPoolConfig;
  7. public class RedisCluster {
  8. public static void main(String[] args) {
  9. //初始化集合,用於裝下面的多個主機和端口
  10. HashSet<HostAndPort> nodes = new HashSet<HostAndPort>();
  11. //創建多個主機和端口實例
  12. HostAndPort hostAndPort = new HostAndPort("192.168.33.130", 7000);
  13. HostAndPort hostAndPort1 = new HostAndPort("192.168.33.130", 7001);
  14. HostAndPort hostAndPort2 = new HostAndPort("192.168.33.130", 7002);
  15. HostAndPort hostAndPort3 = new HostAndPort("192.168.33.130", 7003);
  16. HostAndPort hostAndPort4 = new HostAndPort("192.168.33.130", 7004);
  17. HostAndPort hostAndPort5 = new HostAndPort("192.168.33.130", 7005);
  18. //添加多個主機和端口到集合中
  19. nodes.add(hostAndPort);
  20. nodes.add(hostAndPort1);
  21. nodes.add(hostAndPort2);
  22. nodes.add(hostAndPort3);
  23. nodes.add(hostAndPort4);
  24. nodes.add(hostAndPort5);
  25. //創建config
  26. JedisPoolConfig poolConfig = new JedisPoolConfig();
  27. //通過config創建集群實例
  28. JedisCluster jedisCluster = new JedisCluster(nodes,poolConfig);
  29. //獲取集群中的key為name鍵的值
  30. String str = jedisCluster.get("name");
  31. System.out.println(str);
  32. }
  33. }


打印結果:

技術分享

Redis主從復制和集群配置