|
NoSQL數據庫-集羣篇java |
目 錄node
1 要講的內容 3redis
2 redis集羣簡介 3shell
2.1 集羣的概念 3數據庫
3.1 概念 4網絡
3.2 特色 4併發
4.2.2 自動故障切換(Automatic failover) 8
1 要講的內容
(1)Redis集羣概述
(2)Redis主從複製
(3)Redis哨兵模型
(4)Redis-Cluster集羣(重點)
2 redis集羣簡介
2.1 集羣的概念
所謂的集羣,就是經過添加服務器的數量,提供相同的服務,從而讓服務器達到一個穩定、高效的狀態。
2.1.1 使用redis集羣的必要性
問題:咱們已經部署好了redis,而且能啓動一個redis,實現數據的讀寫,爲何還要學習redis集羣?
答:(1)單個redis存在不穩定性。當redis服務宕機了,就沒有可用的服務了。
(2)單個redis的讀寫能力是有限的。
總結:redis集羣是爲了強化redis的讀寫能力。
2.1.2 如何學習redis集羣
--說明:(1)redis集羣中,每個redis稱之爲一個節點。
(2)redis集羣中,有兩種類型的節點:主節點(master)、從節點(slave)。
(3)redis集羣,是基於redis主從複製實現。
因此,學習redis集羣,就是從學習redis主從複製模型開始的。
3 redis主從複製
3.1 概念
主從複製模型中,有多個redis節點。
其中,有且僅有一個爲主節點Master。從節點Slave能夠有多個。
只要網絡鏈接正常,Master會一直將本身的數據更新同步給Slaves,保持主從同步。
|
3.2 特色
(1)主節點Master可讀、可寫.
(2)從節點Slave只讀。(read-only)
所以,主從模型能夠提升讀的能力,在必定程度上緩解了寫的能力。由於能寫仍然只有Master節點一個,能夠將讀的操做所有移交到從節點上,變相提升了寫能力。
3.3 基於配置實現
3.3.1 需求
主節點 |
6380 |
從節點(兩個) |
638一、6382 |
3.3.2 配置步驟
(1)在/usr/local目錄下,建立一個/redis/master-slave目錄
[root@node0719 local]# mkdir -p redis/master-slave |
(2)在master-slave目錄下,建立三個子目錄6380、638一、6382
[root@node0719 master-slave]# mkdir 6380 6381 6382 |
(3)依次拷貝redis解壓目錄下的redis.conf配置文件,到這三個子目錄中。
[root@node0719 master-slave]# cp /root/redis-3.2.9/redis.conf ./6380/ [root@node0719 master-slave]# cp /root/redis-3.2.9/redis.conf ./6381/ [root@node0719 master-slave]# cp /root/redis-3.2.9/redis.conf ./6382/ |
(4)進入6380目錄,修改redis.conf,將port端口修改爲6380便可。
[root@node0719 master-slave]# cd ./6380 [root@node0719 6380]# vim redis.conf
|
(5)進入6381目錄,修改redis.conf,將port端口改爲6381,同時指定開啓主從複製。
[root@node0719 6380]# cd ../6381 [root@node0719 6381]# vim redis.conf
|
(6)進入6382目錄,修改redis.conf,將port端口改爲6382,同時指定開啓主從複製。
[root@node0719 6380]# cd ../6382 [root@node0719 6381]# vim redis.conf
|
3.3.3 測試
(1)打開三個xshell窗口,在每個窗口中,啓動一個redis節點。查看日誌輸出。(不要改爲後臺模式啓動,看不到日誌,不直觀)
[root@node0719 master-slave]# cd 6380 && redis-server ./redis.conf |
[root@node0719 master-slave]# cd 6381 && redis-server ./redis.conf |
[root@node0719 master-slave]# cd 6382 && redis-server ./redis.conf |
(2)另外再打開三個xshell窗口,在每個窗口中,登錄一個redis節點
[root@node0719 ~]# redis-cli -p 6380 |
[root@node0719 ~]# redis-cli -p 6381 |
[root@node0719 ~]# redis-cli -p 6382 |
(3)在主節點6380上,進行讀寫操做,操做成功
[root@node0719 ~]# redis-cli -p 6380 127.0.0.1:6380> set user:name zs OK 127.0.0.1:6380> get user:name "zs" 127.0.0.1:6380> |
(4)在從節點6381上
讀操做執行成功,而且成功從6380上同步了數據
[root@node0719 ~]# redis-cli -p 6381 127.0.0.1:6381> get user:name "zs" |
寫操做執行失敗。(從節點,只能讀,不能寫)
127.0.0.1:6381> set user:age 18 (error) READONLY You can't write against a read only slave. |
4 Sentinel哨兵模式
4.1 主從模式的缺陷
當主節點宕機了,整個集羣就沒有可寫的節點了。
因爲從節點上備份了主節點的全部數據,那在主節點宕機的狀況下,若是可以將從節點變成一個主節點,是否是就能夠解決這個問題了呢?
答:是的,這個就是Sentinel哨兵的做用。
4.2 哨兵的任務
Redis 的 Sentinel 系統用於管理多個 Redis 服務器(instance), 該系統執行如下三個任務:
監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運做正常。
提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 能夠經過 API 向管理員或者其餘應用程序發送通知。
自動故障遷移(Automatic failover): 當一個主服務器不能正常工做時, Sentinel 會開始一次自動故障遷移操做, 它會進行選舉,將其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其餘從服務器改成複製新的主服務器; 當客戶端試圖鏈接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可使用新主服務器代替失效服務器。
4.2.1 監控(Monitoring)
(1)Sentinel能夠監控任意多個Master和該Master下的Slaves。(即多個主從模式)
(2)同一個哨兵下的、不一樣主從模型,彼此之間相互獨立。
(3)Sentinel會不斷檢查Master和Slaves是否正常。
|
4.2.2 自動故障切換(Automatic failover)
4.2.2.1 Sentinel網絡
監控同一個Master的Sentinel會自動鏈接,組成一個分佈式的Sentinel網絡,互相通訊並交換彼此關於被監視服務器的信息。下圖中,三個監控s1的Sentinel,自動組成Sentinel網絡結構。
|
疑問:爲何要使用sentinel網絡呢?
答:當只有一個sentinel的時候,若是這個sentinel掛掉了,那麼就沒法實現自動故障切換了。
在sentinel網絡中,只要還有一個sentinel活着,就能夠實現故障切換。
4.2.2.2 故障切換的過程
(1)投票(半數原則)
當任何一個Sentinel發現被監控的Master下線時,會通知其它的Sentinel開會,投票肯定該Master是否下線(半數以上,因此sentinel一般配奇數個)。
(2)選舉
當Sentinel肯定Master下線後,會在全部的Slaves中,選舉一個新的節點,升級成Master節點。
其它Slaves節點,轉爲該節點的從節點。
(1)投票 (2)選舉 |
(3)原Master從新上線
當原Master節點從新上線後,自動轉爲當前Master節點的從節點。
(3)原master從新上線 |
4.3 哨兵模式部署
4.3.1 需求
前提:已經存在一個正在運行的主從模式。
另外,配置三個Sentinel實例,監控同一個Master節點。
4.3.2 配置Sentinel
(1)在/usr/local目錄下,建立/redis/sentinels/目錄
[root@node0719 local]# mkdir -p redis/sentinels |
(2)在/sentinels目錄下,以次建立s一、s二、s3三個子目錄中
[root@node0719 sentinels]# mkdir s1 s2 s3 |
(3)依次拷貝redis解壓目錄下的sentinel.conf文件,到這三個子目錄中
[root@node0719 sentinels]# cp /root/redis-3.2.9/sentinel.conf ./s1/ [root@node0719 sentinels]# cp /root/redis-3.2.9/sentinel.conf ./s2/ [root@node0719 sentinels]# cp /root/redis-3.2.9/sentinel.conf ./s3/ |
(4)依次修改s一、s二、s3子目錄中的sentinel.conf文件,修改端口,並指定要監控的主節點。(從節點不須要指定,sentinel會自動識別)
S1哨兵配置以下:
|
S2哨兵配置以下:
|
S3哨兵配置以下:
|
(5)再打開三個xshell窗口,在每個窗口中,啓動一個哨兵實例,並觀察日誌輸出
[root@node0719 sentinels]# redis-sentinel ./s1/sentinel.conf |
[root@node0719 sentinels]# redis-sentinel ./s2/sentinel.conf |
[root@node0719 sentinels]# redis-sentinel ./s3/sentinel.conf |
核心日誌輸出:
|
4.3.3 測試
(1)先關閉6380節點。發現,確實從新指定了一個主節點
|
(2)再次上線6380節點。發現,6380節點成爲了新的主節點的從節點。
|
4.4 結論
Sentinel哨兵模式,確實能實現自動故障切換。提供穩定的服務。
4.5 注意事項
若是哨兵和redis節點不在同一臺服務器上,注意IP綁定的問題。
(1)主從模型,全部的節點,使用ip綁定
|
(2)全部的哨兵,也都使用ip去綁定主機
|
(3)全部的哨兵,都是經過主節點的ip,去監控主從模型
|
5 Redis-cluster集羣
5.1 哨兵模式的缺陷
在哨兵模式中,仍然只有一個Master節點。當併發寫請求較大時,哨兵模式並不能緩解寫壓力。
咱們知道只有主節點才具備寫能力,那若是在一個集羣中,可以配置多個主節點,是否是就能夠緩解寫壓力了呢?
答:是的。這個就是redis-cluster集羣模式。
5.2 Redis-cluster集羣概念
(1)由多個Redis服務器組成的分佈式網絡服務集羣;
(2)集羣之中有多個Master主節點,每個主節點均可讀可寫;
(3)節點之間會互相通訊,兩兩相連;
(4)Redis集羣無中心節點。
|
5.3 集羣節點複製
|
在Redis-Cluster集羣中,能夠給每個主節點添加從節點,主節點和從節點直接遵循主從模型的特性。
當用戶須要處理更多讀請求的時候,添加從節點能夠擴展系統的讀性能。
5.4 故障轉移
Redis集羣的主節點內置了相似Redis Sentinel的節點故障檢測和自動故障轉移功能,當集羣中的某個主節點下線時,集羣中的其餘在線主節點會注意到這一點,並對已下線的主節點進行故障轉移。
|
集羣進行故障轉移的方法和Redis Sentinel進行故障轉移的方法基本同樣,不一樣的是,在集羣裏面,故障轉移是由集羣中其餘在線的主節點負責進行的,因此集羣沒必要另外使用Redis Sentinel。
5.5 集羣分片策略
Redis-cluster分片策略,是用來解決key存儲位置的。
集羣將整個數據庫分爲16384個槽位slot,全部key-value數據都存儲在這些slot中的某一個上。一個slot槽位能夠存放多個數據,key的槽位計算公式爲:slot_number=crc16(key)%16384,其中crc16爲16位的循環冗餘校驗和函數。
集羣中的每一個主節點均可以處理0個至16383個槽,當16384個槽都有某個節點在負責處理時,集羣進入上線狀態,並開始處理客戶端發送的數據命令請求。
|
5.6 集羣redirect轉向
因爲Redis集羣無中心節點,請求會隨機發給任意主節點;
主節點只會處理本身負責槽位的命令請求,其它槽位的命令請求,該主節點會返回客戶端一個轉向錯誤;
客戶端根據錯誤中包含的地址和端口從新向正確的負責的主節點發起命令請求。
|
5.7 集羣搭建
5.7.1 準備工做
(1)安裝ruby環境
redis集羣管理工具redis-trib.rb依賴ruby環境,首先須要安裝ruby環境:
yum -y install ruby yum -y install rubygems |
(2)安裝ruby和redis的接口程序
拷貝redis-3.0.0.gem至/usr/local下,執行安裝:
gem install /usr/local/redis-3.0.0.gem |
5.7.2 集羣規劃
(1)Redis集羣最少須要6個節點,能夠分佈在一臺或者多臺主機上。
本教案在一臺主機上建立僞分佈式集羣,不一樣的端口表示不一樣的redis節點,以下:
主節點:192.168.56.3:7001 192.168.56.3:7002 192.168.56.3:7003
從節點:192.168.56.3:7004 192.168.56.3:7005 192.168.56.3:7006
(2)在/usr/local/redis下建立redis-cluster目錄,其下建立700一、7002。。7006目錄,以下:
|
(3)將redis解壓路徑下的配置文件redis.conf,依次拷貝到每一個700X目錄內,並修改每一個700X目錄下的redis.conf配置文件:
必選配置: port 700X bind 192.168.23.3 cluster-enabled yes 建議配置: daemonized yes logfile /usr/local/redis/redis-cluster/700X/node.log |
5.7.3 啓動每一個結點redis服務
依次以700X下的redis.conf,啓動redis節點。(必須指定redis.conf文件)
redis-server /usr/local/redis/redis-cluster/700X/redis.conf |
5.7.4 執行建立集羣命令
進入到redis源碼存放目錄redis/redis-4.10.3/src下,執行redis-trib.rb,此腳本是ruby腳本,它依賴ruby環境。
./redis-trib.rb create --replicas 1 192.168.159.10:7001 192.168.159.10:7002 192.168.159.10:7003 192.168.159.10:7004 192.168.159.10:7005 192.168.159.10:7006 |
建立過程以下:
|
5.7.5 查詢集羣信息
集羣建立成功登錄任意redis結點查詢集羣中的節點狀況。
./redis-cli -c -h 192.168.56.3 -p 7001
|
說明:./redis-cli -c -h 192.168.56.3 -p 7001 ,其中:
-c表示以集羣方式鏈接redis, -h指定ip地址, -p指定端口號
cluster nodes 查詢集羣結點信息; cluster info 查詢集羣狀態信。 |
5.8 集羣管理
5.8.1 添加主節點
5.8.1.1 節點規劃
集羣建立成功後能夠向集羣中添加節點,下面是添加一個master主節點
添加7007節點,參考集羣結點規劃章節添加一個「7007」目錄做爲新節點。
添加節點,執行下邊命令:
./redis-trib.rb add-node 192.168.23.3:7007 192.168.23.3:7001
|
查看集羣結點發現7007已添加到集羣中:
|
5.8.1.2 hash槽從新分配
添加完新的主節點後,須要對主節點進行hash槽分配,這樣該主節才能夠存儲數據。
redis集羣有16384個槽,被全部的主節點共同分配,經過查看集羣結點能夠看到槽佔用狀況。
|
給剛添加的7007結點分配槽:
第一步:鏈接上集羣
./redis-trib.rb reshard 192.168.23.3:7001(鏈接集羣中任意一個可用節點都行) |
第二步:輸入要分配的槽數量
|
輸入 500表示要分配500個槽
第三步:輸入接收槽的結點id
|
這裏準備給7007分配槽,經過cluster nodes查看7007結點id爲79bbb30bba66b4997b9360dd09849c67d2d02bb9
輸入:79bbb30bba66b4997b9360dd09849c67d2d02bb9
第四步:輸入源結點id
|
這裏輸入all,表示從其它主節點中分配。
第五步:輸入yes開始移動槽到目標結點id
|
5.8.2 添加從節點
集羣建立成功後能夠向集羣中添加節點,下面是添加一個slave從節點。
添加7008從結點,將7008做爲7007的從結點。
新增從節點命令格式:
./redis-trib.rb add-node --slave --master-id masterID newNodIP:port MasterIP:port
masterID 主節點id,從cluster nodes信息中查看 newNodIP:port 新增節點的ip:端口 MasterIP:port 主節點的ip:端口 |
執行以下命令:
./redis-trib.rb add-node --slave --master-id 909c349f5f2d4db015101fb7c4e3c227a74ad382 192.168.4.253:7008 192.168.4.253:7007 |
79bbb30bba66b4997b9360dd09849c67d2d02bb9 是7007結點的id,可經過cluster nodes查看。
|
注意:
若是原來該結點在集羣中的配置信息已經生成cluster-config-file指定的配置文件中(若是cluster-config-file沒有指定則默認爲nodes.conf),這時可能會報錯:
[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0 |
解決方法:
刪除生成的配置文件nodes.conf,刪除後再執行./redis-trib.rb add-node指令。
查看集羣中的結點,剛添加的7008爲7007的從節點:
|
5.8.3 刪除節點:
刪除節點命令格式:
./redis-trib.rb del-node nodeIP:port nodeID nodeIP:port 待刪除節點的ip:端口 nodeID 待刪除節點的id,從cluster node中查看 |
注意,刪除已經佔有hash槽的結點會失敗,報錯以下:
[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again. |
須要將該結點佔用的hash槽分配出去(參考hash槽從新分配章節)。
6 java程序鏈接redis集羣
6.1 鏈接步驟
6.1.1 第一步:建立項目,導入jar包
|
6.1.2 第二步:建立redis集羣的客戶端
package cn.gzsxt.jedis.test;
import java.util.HashSet; import java.util.Set; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster;
public class TestJedisCluster {
public static void main(String[] args) { //一、建立jedidsCluster客戶端 //建立一個set集合,用來封裝全部redis節點的信息 Set<HostAndPort> nodes = new HashSet<>(); nodes.add(new HostAndPort("192.168.23.12", 7001)); nodes.add(new HostAndPort("192.168.23.12", 7002)); nodes.add(new HostAndPort("192.168.23.12", 7003)); nodes.add(new HostAndPort("192.168.23.12", 7004)); nodes.add(new HostAndPort("192.168.23.12", 7005)); nodes.add(new HostAndPort("192.168.23.12", 7006)); nodes.add(new HostAndPort("192.168.23.12", 7007)); nodes.add(new HostAndPort("192.168.23.12", 7008)); JedisCluster cluster = new JedisCluster(nodes); String name = cluster.get("user:id:1:name"); cluster.set("user:id:1:address", "廣東省廣州市廣州尚學堂"); String address = cluster.get("user:id:1:address"); System.out.println("name:"+name); System.out.println("address:"+address); if(null!=cluster){ cluster.close(); } } } |
6.2 注意事項:
鏈接Redis集羣時,須要修改防火牆,開方每個redis節點的端口。
說明:若是要開發一個範圍的端口,可使用冒號來分割,即: 7001:7008,表示開發7001-7008之間全部的端口
|
6.3 測試
|
訪問Redis-cluster集羣成功!!!