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
配置修改圖示:
配置效果圖示:
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檔案
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
注意:
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叢集,使用命令 :
redis-cli -c -p [port]
檢視叢集中的所有主節點資訊
redis-cli -c -p 7000 cluster nodes [| grep master]
redis叢集新增節點
根據新增節點型別的不同,有兩種方法來新增新節點
1、主節點:如果新增的是主節點,那麼我們需要建立一個空節點,然後將某些雜湊槽移動到這個空節點裡面
2、從節點:如果新增的是從節點,我們也需要建立一個空節點,然後把這個新節點設定成叢集中某個主節點的複製品。
新增節點:
1、首先把需要新增的節點啟動
建立7006目錄,拷貝7000中的redis.conf到7006中,然後修改埠port為7006,修改好後進入7006目錄啟動這個節點:
redis-server redis.conf
2、執行以下命令,將這個新節點新增到叢集中:
redis-trib.rb add-node 192.168.33.130:7006 192.168.33.130:7000
結果圖示:
3、執行命令檢視剛才新增的節點:
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叢集就開始分配雜湊槽了。
至此,一個新的主節點就新增完成了,執行命令檢視現在的叢集中節點的狀態
redis-cli -c -p 7000 cluster nodes
結果圖示:
Redis叢集刪除節點
1、如果刪除的節點是主節點,這裡我們刪除192.168.33.130:7006節點,這個節點有1000個雜湊槽
首先要把節點中的雜湊槽轉移到其他節點中,執行下面的命令:
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);
}
}
列印結果:
---------------------
作者:聆聽的幻樹
來源:CSDN
原文:https://blog.csdn.net/u011204847/article/details/51307044
版權宣告:本文為博主原創文章,轉載請附上博文連結!