色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

集群的作用及搭建方法及設計方案

電子工程師 ? 來源:lq ? 2019-01-15 16:43 ? 次閱讀

在前面的文章中已經介紹了 Redis 的幾種高可用技術:持久化、主從復制和哨兵,但這些方案仍有不足,其中最主要的問題是存儲能力受單機限制,以及無法實現寫操作的負載均衡。

本文將詳細介紹集群,主要內容包括:

集群的作用

集群的搭建方法及設計方案

集群的基本原理

客戶端訪問集群的方法

實踐須知(集群伸縮、故障轉移、參數優化等)

集群的作用

集群,即 Redis Cluster,是 Redis 3.0 開始引入的分布式存儲方案。集群由多個節點(Node)組成,Redis 的數據分布在這些節點中。

集群中的節點分為主節點和從節點:只有主節點負責讀寫請求和集群信息的維護;從節點只進行主節點數據和狀態信息的復制。

集群的作用,可以歸納為兩點:

數據分區

數據分區(或稱數據分片)是集群最核心的功能。集群將數據分散到多個節點:

一方面突破了 Redis 單機內存大小的限制,存儲容量大大增加。

另一方面每個主節點都可以對外提供讀服務和寫服務,大大提高了集群的響應能力。

Redis 單機內存大小受限問題,在介紹持久化和主從復制時都有提及。

例如,如果單機內存太大,bgsave 和 bgrewriteaof 的 fork 操作可能導致主進程阻塞,主從環境下主機切換時可能導致從節點長時間無法提供服務,全量復制階段主節點的復制緩沖區可能溢出。

高可用

集群支持主從復制和主節點的自動故障轉移(與哨兵類似),當任一節點發生故障時,集群仍然可以對外提供服務。本文內容基于 Redis 3.0.6。

集群的搭建

我們將搭建一個簡單的集群:共 6 個節點,3 主 3 從。方便起見,所有節點在同一臺服務器上,以端口號進行區分,配置從簡。

3個主節點端口號:7000/7001/7002;對應的從節點端口號:8000/8001/8002。

集群的搭建有兩種方式:

手動執行 Redis 命令,一步步完成搭建

使用 Ruby 腳本搭建

兩者搭建的原理是一樣的,只是 Ruby 腳本將 Redis 命令進行了打包封裝;在實際應用中推薦使用腳本方式,簡單快捷不容易出錯。下面分別介紹這兩種方式。

執行 Redis 命令搭建集群

集群的搭建可以分為四步:

啟動節點:將節點以集群模式啟動,此時節點是獨立的,并沒有建立聯系。

節點握手:讓獨立的節點連成一個網絡

分配槽:將 16384 個槽分配給主節點。

指定主從關系:為從節點指定主節點。

實際上,前三步完成后集群便可以對外提供服務;但指定從節點后,集群才能夠提供真正高可用的服務。

啟動節點

集群節點的啟動仍然是使用 redis-server 命令,但需要使用集群模式啟動。

下面是 7000 節點的配置文件(只列出了節點正常工作關鍵配置,其他配置,如開啟 AOF,可以參照單機節點進行):

#redis-7000.confport7000cluster-enabledyescluster-config-file"node-7000.conf"logfile"log-7000.log"dbfilename"dump-7000.rdb"daemonizeyes

其中的 cluster-enabled 和 cluster-config-file 是與集群相關的配置。

cluster-enabledyes:Redis 實例可以分為單機模式(standalone)和集群模式(cluster);cluster-enabledyes 可以啟動集群模式。

在單機模式下啟動的 Redis 實例,如果執行 info server 命令,可以發現 redis_mode 一項為 standalone,如下圖所示:

集群模式下的節點,其 redis_mode 為 cluster,如下圖所示:

cluster-config-file:該參數指定了集群配置文件的位置。每個節點在運行過程中,會維護一份集群配置文件。

每當集群信息發生變化時(如增減節點),集群內所有節點會將最新信息更新到該配置文件。

當節點重啟后,會重新讀取該配置文件,獲取集群信息,可以方便的重新加入到集群中。

也就是說,當 Redis 節點以集群模式啟動時,會首先尋找是否有集群配置文件。

如果有則使用文件中的配置啟動;如果沒有,則初始化配置并將配置保存到文件中。集群配置文件由 Redis 節點維護,不需要人工修改。

編輯好配置文件后,使用 redis-server 命令啟動該節點:

redis-serverredis-7000.conf

節點啟動以后,通過 cluster nodes 命令可以查看節點的情況,如下圖所示:

其中返回值第一項表示節點 id,由 40 個 16 進制字符串組成,節點 id 與主從復制一文中提到的 runId 不同。

Redis 每次啟動 runId 都會重新創建,但是節點 id 只在集群初始化時創建一次,然后保存到集群配置文件中,以后節點重新啟動時會直接在集群配置文件中讀取。

其他節點使用相同辦法啟動,不再贅述。需要特別注意,在啟動節點階段,節點是沒有主從關系的,因此從節點不需要加 slaveof 配置。

節點握手

節點啟動以后是相互獨立的,并不知道其他節點存在;需要進行節點握手,將獨立的節點組成一個網絡。

節點握手使用 cluster meet {ip} {port} 命令實現,例如在 7000 節點中執行 clustermeet 192.168.72.128 7001,可以完成 7000 節點和 7001 節點的握手。

注意:ip 使用的是局域網 ip,而不是 localhost 或 127.0.0.1,是為了其他機器上的節點或客戶端也可以訪問。

此時再使用 cluster nodes 查看:

在 7001 節點下也可以類似查看:

同理,在 7000 節點中使用 cluster meet 命令,可以將所有節點加入到集群,完成節點握手:

clustermeet192.168.72.1287002clustermeet192.168.72.1288000clustermeet192.168.72.1288001clustermeet192.168.72.1288002

執行完上述命令后,可以看到 7000 節點已經感知到了所有其他節點:

通過節點之間的通信,每個節點都可以感知到所有其他節點,以 8000 節點為例:

分配槽

在 Redis 集群中,借助槽實現數據分區,具體原理后文會介紹。集群有 16384 個槽,槽是數據管理和遷移的基本單位。

當數據庫中的 16384 個槽都分配了節點時,集群處于上線狀態(ok);如果有任意一個槽沒有分配節點,則集群處于下線狀態(fail)。

cluster info 命令可以查看集群狀態,分配槽之前狀態為 fail:

分配槽使用 cluster addslots 命令,執行下面的命令將槽(編號 0-16383)全部分配完畢:

redis-cli-p7000clusteraddslots{0..5461}redis-cli-p7001clusteraddslots{5462..10922}redis-cli-p7002clusteraddslots{10923..16383}

此時查看集群狀態,顯示所有槽分配完畢,集群進入上線狀態:

指定主從關系

集群中指定主從關系不再使用 slaveof 命令,而是使用 cluster replicate 命令;參數使用節點 id。

通過 cluster nodes 獲得幾個主節點的節點 id 后,執行下面的命令為每個從節點指定主節點:

redis-cli-p8000clusterreplicatebe816eba968bc16c884b963d768c945e86ac51aeredis-cli-p8001clusterreplicate788b361563acb175ce8232569347812a12f1fdb4redis-cli-p8002clusterreplicatea26f1624a3da3e5197dde267de683d61bb2dcbf1

此時執行 cluster nodes 查看各個節點的狀態,可以看到主從關系已經建立:

至此,集群搭建完畢。

使用 Ruby 腳本搭建集群

在 {REDIS_HOME}/src 目錄下可以看到 redis-trib.rb 文件,這是一個 Ruby 腳本,可以實現自動化的集群搭建。

①安裝 Ruby 環境

以 Ubuntu 為例,如下操作即可安裝 Ruby 環境:

apt-get install ruby # 安裝 Ruby 環境。

gem install redis #gem 是 Ruby 的包管理工具,該命令可以安裝 ruby-redis 依賴。

②啟動節點

與第一種方法中的“啟動節點”完全相同。

③搭建集群

redis-trib.rb 腳本提供了眾多命令,其中 create 用于搭建集群,使用方法如下:

./redis-trib.rbcreate--replicas1192.168.72.128:7000192.168.72.128:7001192.168.72.128:7002192.168.72.128:8000192.168.72.128:8001192.168.72.128:8002

其中:--replicas=1 表示每個主節點有 1 個從節點;后面的多個 {ip:port} 表示節點地址,前面的做主節點,后面的做從節點。使用 redis-trib.rb 搭建集群時,要求節點不能包含任何槽和數據。

執行創建命令后,腳本會給出創建集群的計劃,如下圖所示;計劃包括哪些是主節點,哪些是從節點,以及如何分配槽。

輸入 yes 確認執行計劃,腳本便開始按照計劃執行,如下圖所示:

至此,集群搭建完畢。

集群方案設計

設計集群方案時,至少要考慮以下因素:

高可用要求:根據故障轉移的原理,至少需要 3 個主節點才能完成故障轉移,且 3 個主節點不應在同一臺物理機上。

每個主節點至少需要 1 個從節點,且主從節點不應在一臺物理機上;因此高可用集群至少包含 6 個節點。

數據量和訪問量:估算應用需要的數據量和總訪問量(考慮業務發展,留有冗余),結合每個主節點的容量和能承受的訪問量(可以通過 benchmark 得到較準確估計),計算需要的主節點數量。

節點數量限制:Redis 官方給出的節點數量限制為 1000,主要是考慮節點間通信帶來的消耗。

在實際應用中應盡量避免大集群,如果節點數量不足以滿足應用對 Redis 數據量和訪問量的要求,可以考慮:①業務分割,大集群分為多個小集群;②減少不必要的數據;③調整數據過期策略等。

適度冗余:Redis 可以在不影響集群服務的情況下增加節點,因此節點數量適當冗余即可,不用太大。

集群的基本原理

上面介紹了集群的搭建方法和設計方案,下面將進一步深入,介紹集群的原理。

集群最核心的功能是數據分區,因此:

首先介紹數據的分區規則。

然后介紹集群實現的細節:通信機制和數據結構。

最后以 cluster meet(節點握手)、cluster addslots(槽分配)為例,說明節點是如何利用上述數據結構和通信機制實現集群命令的。

數據分區方案

數據分區有順序分區、哈希分區等,其中哈希分區由于其天然的隨機性,使用廣泛;集群的分區方案便是哈希分區的一種。

哈希分區的基本思路是:對數據的特征值(如 key)進行哈希,然后根據哈希值決定數據落在哪個節點。

常見的哈希分區包括:哈希取余分區、一致性哈希分區、帶虛擬節點的一致性哈希分區等。

衡量數據分區方法好壞的標準有很多,其中比較重要的兩個因素是:

數據分布是否均勻。

增加或刪減節點對數據分布的影響。

由于哈希的隨機性,哈希分區基本可以保證數據分布均勻;因此在比較哈希分區方案時,重點要看增減節點對數據分布的影響。

哈希取余分區

哈希取余分區思路非常簡單:計算 key 的 hash 值,然后對節點數量進行取余,從而決定數據映射到哪個節點上。

該方案最大的問題是,當新增或刪減節點時,節點數量發生變化,系統中所有的數據都需要重新計算映射關系,引發大規模數據遷移。

一致性哈希分區

一致性哈希算法將整個哈希值空間組織成一個虛擬的圓環,如下圖所示,范圍為 0-2^32-1。

對于每個數據,根據 key 計算 hash 值,確定數據在環上的位置,然后從此位置沿環順時針行走,找到的第一臺服務器就是其應該映射到的服務器。

與哈希取余分區相比,一致性哈希分區將增減節點的影響限制在相鄰節點。

以上圖為例,如果在 node1 和 node2 之間增加 node5,則只有 node2 中的一部分數據會遷移到 node5;如果去掉 node2,則原 node2 中的數據只會遷移到 node4 中,只有 node4 會受影響。

一致性哈希分區的主要問題在于,當節點數量較少時,增加或刪減節點,對單個節點的影響可能很大,造成數據的嚴重不平衡。

還是以上圖為例,如果去掉 node2,node4 中的數據由總數據的 1/4 左右變為 1/2 左右,與其他節點相比負載過高。

帶虛擬節點的一致性哈希分區

該方案在一致性哈希分區的基礎上,引入了虛擬節點的概念。Redis 集群使用的便是該方案,其中的虛擬節點稱為槽(slot)。

槽是介于數據和實際節點之間的虛擬概念;每個實際節點包含一定數量的槽,每個槽包含哈希值在一定范圍內的數據。

引入槽以后,數據的映射關系由數據 hash->實際節點,變成了數據 hash->槽->實際節點。

在使用了槽的一致性哈希分區中,槽是數據管理和遷移的基本單位。槽解耦了數據和實際節點之間的關系,增加或刪除節點對系統的影響很小。

仍以上圖為例,系統中有 4 個實際節點,假設為其分配 16 個槽(0-15);槽 0-3 位于 node1,4-7 位于 node2,以此類推。

如果此時刪除 node2,只需要將槽 4-7 重新分配即可,例如槽 4-5 分配給 node1,槽 6 分配給 node3,槽 7 分配給 node4;可以看出刪除 node2 后,數據在其他節點的分布仍然較為均衡。

槽的數量一般遠小于 2^32,遠大于實際節點的數量;在 Redis 集群中,槽的數量為 16384。

上面這張圖很好的總結了 Redis 集群將數據映射到實際節點的過程:

Redis 對數據的特征值(一般是key)計算哈希值,使用的算法是 CRC16。

根據哈希值,計算數據屬于哪個槽。

根據槽與節點的映射關系,計算數據屬于哪個節點。

節點通信機制

集群要作為一個整體工作,離不開節點之間的通信。

兩個端口

在哨兵系統中,節點分為數據節點和哨兵節點:前者存儲數據,后者實現額外的控制功能。

在集群中,沒有數據節點與非數據節點之分:所有的節點都存儲數據,也都參與集群狀態的維護。

為此,集群中的每個節點,都提供了兩個 TCP 端口:

普通端口:即我們在前面指定的端口(7000 等)。普通端口主要用于為客戶端提供服務(與單機節點類似);但在節點間數據遷移時也會使用。

集群端口:端口號是普通端口+10000(10000 是固定值,無法改變),如 7000 節點的集群端口為 17000。

集群端口只用于節點之間的通信,如搭建集群、增減節點、故障轉移等操作時節點間的通信;不要使用客戶端連接集群接口。為了保證集群可以正常工作,在配置防火墻時,要同時開啟普通端口和集群端口。

Gossip 協議

節點間通信,按照通信協議可以分為幾種類型:單對單、廣播、Gossip 協議等。重點是廣播和 Gossip 的對比。

廣播是指向集群內所有節點發送消息;優點是集群的收斂速度快(集群收斂是指集群內所有節點獲得的集群信息是一致的),缺點是每條消息都要發送給所有節點,CPU、帶寬等消耗較大。

Gossip 協議的特點是:在節點數量有限的網絡中,每個節點都“隨機”的與部分節點通信(并不是真正的隨機,而是根據特定的規則選擇通信的節點),經過一番雜亂無章的通信,每個節點的狀態很快會達到一致。

Gossip 協議的優點有負載(比廣播)低、去中心化、容錯性高(因為通信有冗余)等;缺點主要是集群的收斂速度慢。

消息類型

集群中的節點采用固定頻率(每秒 10 次)的定時任務進行通信相關的工作:判斷是否需要發送消息及消息類型、確定接收節點、發送消息等。

如果集群狀態發生了變化,如增減節點、槽狀態變更,通過節點間的通信,所有節點會很快得知整個集群的狀態,使集群收斂。

節點間發送的消息主要分為 5 種:

MEET 消息

PING 消息

PONG 消息

FAIL 消息

PUBLISH 消息

不同的消息類型,通信協議、發送的頻率和時機、接收節點的選擇等是不同的:

MEET 消息:在節點握手階段,當節點收到客戶端的 cluster meet 命令時,會向新加入的節點發送 MEET 消息,請求新節點加入到當前集群;新節點收到 MEET 消息后會回復一個 PONG 消息。

PING 消息:集群里每個節點每秒鐘會選擇部分節點發送 PING 消息,接收者收到消息后會回復一個 PONG 消息。PING 消息的內容是自身節點和部分其他節點的狀態信息;作用是彼此交換信息,以及檢測節點是否在線。

PING 消息使用 Gossip 協議發送,接收節點的選擇兼顧了收斂速度和帶寬成本,具體規則如下:①隨機找 5 個節點,在其中選擇最久沒有通信的 1 個節點。②掃描節點列表,選擇最近一次收到 PONG 消息時間大于 cluster_node_timeout/2 的所有節點,防止這些節點長時間未更新。

PONG 消息:PONG 消息封裝了自身狀態數據??梢苑譃閮煞N:第一種是在接到 MEET/PING 消息后回復的 PONG 消息;第二種是指節點向集群廣播 PONG 消息。

這樣其他節點可以獲知該節點的最新信息,例如故障恢復后新的主節點會廣播 PONG 消息。

FAIL 消息:當一個主節點判斷另一個主節點進入 FAIL 狀態時,會向集群廣播這一 FAIL 消息;接收節點會將這一 FAIL 消息保存起來,便于后續的判斷。

PUBLISH 消息:節點收到 PUBLISH 命令后,會先執行該命令,然后向集群廣播這一消息,接收節點也會執行該 PUBLISH 命令。

數據結構

節點需要專門的數據結構來存儲集群的狀態。所謂集群的狀態,是一個比較大的概念,包括:集群是否處于上線狀態、集群中有哪些節點、節點是否可達、節點的主從狀態、槽的分布……

節點為了存儲集群狀態而提供的數據結構中,最關鍵的是 clusterNode 和 clusterState 結構:前者記錄了一個節點的狀態,后者記錄了集群作為一個整體的狀態。

clusterNode

clusterNode 結構保存了一個節點的當前狀態,包括創建時間、節點 id、ip 和端口號等。

每個節點都會用一個 clusterNode 結構記錄自己的狀態,并為集群內所有其他節點都創建一個 clusterNode 結構來記錄節點狀態。

下面列舉了 clusterNode 的部分字段,并說明了字段的含義和作用:

typedefstructclusterNode{//節點創建時間mstime_tctime;//節點idcharname[REDIS_CLUSTER_NAMELEN];//節點的ip和端口號charip[REDIS_IP_STR_LEN];intport;//節點標識:整型,每個bit都代表了不同狀態,如節點的主從狀態、是否在線、是否在握手等intflags;//配置紀元:故障轉移時起作用,類似于哨兵的配置紀元uint64_tconfigEpoch;//槽在該節點中的分布:占用16384/8個字節,16384個比特;每個比特對應一個槽:比特值為1,則該比特對應的槽在節點中;比特值為0,則該比特對應的槽不在節點中unsignedcharslots[16384/8];//節點中槽的數量intnumslots;…………}clusterNode;

除此之外,clusterState 還包括故障轉移、槽遷移等需要的信息。

集群命令的實現

這一部分將以 cluster meet(節點握手)、cluster addslots(槽分配)為例,說明節點是如何利用上述數據結構和通信機制實現集群命令的。

cluster meet

假設要向 A 節點發送 cluster meet 命令,將 B 節點加入到 A 所在的集群,則 A 節點收到命令后,執行的操作如下:

A 為 B 創建一個 clusterNode 結構,并將其添加到 clusterState 的 nodes 字典中。

A 向 B 發送 MEET 消息。

B 收到 MEET 消息后,會為 A 創建一個 clusterNode 結構,并將其添加到 clusterState 的 nodes 字典中。

B 回復 A 一個 PONG 消息。

A 收到 B 的 PONG 消息后,便知道 B 已經成功接收自己的 MEET 消息。

然后,A 向 B 返回一個 PING 消息。

B 收到 A 的 PING 消息后,便知道 A 已經成功接收自己的 PONG 消息,握手完成。

之后,A 通過 Gossip 協議將 B 的信息廣播給集群內其他節點,其他節點也會與 B 握手;一段時間后,集群收斂,B 成為集群內的一個普通節點。

通過上述過程可以發現,集群中兩個節點的握手過程與 TCP 類似,都是三次握手:A 向 B 發送 MEET;B 向 A 發送 PONG;A 向 B 發送 PING。

cluster addslots

集群中槽的分配信息,存儲在 clusterNode 的 slots 數組和 clusterState 的 slots 數組中,兩個數組的結構前面已做介紹。

二者的區別在于:前者存儲的是該節點中分配了哪些槽,后者存儲的是集群中所有槽分別分布在哪個節點。

cluster addslots 命令接收一個槽或多個槽作為參數,例如在 A 節點上執行 cluster addslots {0..10} 命令,是將編號為 0-10 的槽分配給 A 節點。

具體執行過程如下:

遍歷輸入槽,檢查它們是否都沒有分配,如果有一個槽已分配,命令執行失??;方法是檢查輸入槽在 clusterState.slots[] 中對應的值是否為 NULL。

遍歷輸入槽,將其分配給節點 A;方法是修改 clusterNode.slots[] 中對應的比特為 1,以及 clusterState.slots[] 中對應的指針指向 A 節點。

A 節點執行完成后,通過節點通信機制通知其他節點,所有節點都會知道 0-10 的槽分配給了 A 節點。

客戶端訪問集群

在集群中,數據分布在不同的節點中,客戶端通過某節點訪問數據時,數據可能不在該節點中;下面介紹集群是如何處理這個問題的。

redis-cli

當節點收到 redis-cli 發來的命令(如 set/get)時,過程如下:

①計算 key 屬于哪個槽:CRC16(key) &16383。

集群提供的 cluster keyslot 命令也是使用上述公式實現,如:

②判斷 key 所在的槽是否在當前節點:假設 key 位于第 i 個槽,clusterState.slots[i] 則指向了槽所在的節點。

如果 clusterState.slots[i]==clusterState.myself,說明槽在當前節點,可以直接在當前節點執行命令。

否則,說明槽不在當前節點,則查詢槽所在節點的地址(clusterState.slots[i].ip/port),并將其包裝到 MOVED 錯誤中返回給 redis-cli。

③redis-cli 收到 MOVED 錯誤后,根據返回的 ip 和 port 重新發送請求。

下面的例子展示了 redis-cli 和集群的互動過程:在 7000 節點中操作 key1,但 key1 所在的槽 9189 在節點 7001 中。

因此節點返回 MOVED 錯誤(包含 7001 節點的 ip 和 port)給 redis-cli,redis-cli 重新向 7001 發起請求。

上例中,redis-cli 通過 -c 指定了集群模式,如果沒有指定,redis-cli 無法處理 MOVED 錯誤:

Smart 客戶端

redis-cli 這一類客戶端稱為 Dummy 客戶端,因為它們在執行命令前不知道數據在哪個節點,需要借助 MOVED 錯誤重新定向。與 Dummy 客戶端相對應的是 Smart 客戶端。

Smart 客戶端(以 Java 的 JedisCluster 為例)的基本原理如下:

①JedisCluster 初始化時,在內部維護 slot->node 的緩存,方法是連接任一節點,執行 cluster slots 命令,該命令返回如下所示:

②此外,JedisCluster 為每個節點創建連接池(即 JedisPool)。

③當執行命令時,JedisCluster 根據 key->slot->node 選擇需要連接的節點,發送命令。

如果成功,則命令執行完畢;如果執行失敗,則會隨機選擇其他節點進行重試,并在出現 MOVED 錯誤時,使用 cluster slots 重新同步 slot->node 的映射關系。

下面代碼演示了如何使用 JedisCluster 訪問集群(未考慮資源釋放、異常處理等):

publicstaticvoidtest(){Setnodes=newHashSet<>();nodes.add(newHostAndPort("192.168.72.128",7000));nodes.add(newHostAndPort("192.168.72.128",7001));nodes.add(newHostAndPort("192.168.72.128",7002));nodes.add(newHostAndPort("192.168.72.128",8000));nodes.add(newHostAndPort("192.168.72.128",8001));nodes.add(newHostAndPort("192.168.72.128",8002));JedisClustercluster=newJedisCluster(nodes);System.out.println(cluster.get("key1"));cluster.close();}

注意事項如下:

JedisCluster 中已經包含所有節點的連接池,因此 JedisCluster 要使用單例。

客戶端維護了 slot->node 映射關系以及為每個節點創建了連接池,當節點數量較多時,應注意客戶端內存資源和連接資源的消耗。

Jedis 較新版本針對 JedisCluster 做了一些性能方面的優化,如 cluster slots 緩存更新和鎖阻塞等方面的優化,應盡量使用 2.8.2 及以上版本的 Jedis。

實踐須知

前面介紹了集群正常運行和訪問的方法和原理,下面是一些重要的補充內容。

集群伸縮

實踐中常常需要對集群進行伸縮,如訪問量增大時的擴容操作。Redis 集群可以在不影響對外服務的情況下實現伸縮;伸縮的核心是槽遷移:修改槽與節點的對應關系,實現槽(即數據)在節點之間的移動。

例如,如果槽均勻分布在集群的 3 個節點中,此時增加一個節點,則需要從 3 個節點中分別拿出一部分槽給新節點,從而實現槽在 4 個節點中的均勻分布。

增加節點

假設要增加 7003 和 8003 節點,其中 8003 是 7003 的從節點,步驟如下:

①啟動節點:方法參見集群搭建。

②節點握手:可以使用 cluster meet 命令,但在生產環境中建議使用 redis-trib.rb 的 add-node 工具,其原理也是 cluster meet,但它會先檢查新節點是否已加入其他集群或者存在數據,避免加入到集群后帶來混亂。

redis-trib.rbadd-node192.168.72.128:7003192.168.72.1287000redis-trib.rbadd-node192.168.72.128:8003192.168.72.1287000

③遷移槽:推薦使用 redis-trib.rb 的 reshard 工具實現。reshard 自動化程度很高,只需要輸入 redis-trib.rb reshard ip:port (ip 和 port 可以是集群中的任一節點)。

然后按照提示輸入以下信息,槽遷移會自動完成:

待遷移的槽數量:16384 個槽均分給 4 個節點,每個節點 4096 個槽,因此待遷移槽數量為 4096。

目標節點 id:7003 節點的 id。

源節點的 id:7000/7001/7002 節點的 id。

④指定主從關系:方法參見集群搭建。

減少節點

假設要下線 7000/8000 節點,可以分為兩步:

遷移槽:使用 reshard 將 7000 節點中的槽均勻遷移到 7001/7002/7003 節點。

下線節點:使用 redis-trib.rb del-node 工具;應先下線從節點再下線主節點,因為若主節點先下線,從節點會被指向其他主節點,造成不必要的全量復制。

redis-trib.rbdel-node192.168.72.128:7001{節點8000的id}redis-trib.rbdel-node192.168.72.128:7001{節點7000的id}

ASK 錯誤

集群伸縮的核心是槽遷移。在槽遷移過程中,如果客戶端向源節點發送命令,源節點執行流程如下:

客戶端收到 ASK 錯誤后,從中讀取目標節點的地址信息,并向目標節點重新發送請求,就像收到 MOVED 錯誤時一樣。

但是二者有很大區別:ASK 錯誤說明數據正在遷移,不知道何時遷移完成,因此重定向是臨時的,SMART 客戶端不會刷新 slots 緩存;MOVED 錯誤重定向則是(相對)永久的,SMART 客戶端會刷新 slots 緩存。

故障轉移

在哨兵一文中,介紹了哨兵實現故障發現和故障轉移的原理。

雖然細節上有很大不同,但集群的實現與哨兵思路類似:通過定時任務發送 PING 消息檢測其他節點狀態;節點下線分為主觀下線和客觀下線;客觀下線后選取從節點進行故障轉移。

與哨兵一樣,集群只實現了主節點的故障轉移;從節點故障時只會被下線,不會進行故障轉移。

因此,使用集群時,應謹慎使用讀寫分離技術,因為從節點故障會導致讀服務不可用,可用性變差。

這里不再詳細介紹故障轉移的細節,只對重要事項進行說明:

節點數量:在故障轉移階段,需要由主節點投票選出哪個從節點成為新的主節點;從節點選舉勝出需要的票數為 N/2+1;其中 N 為主節點數量(包括故障主節點),但故障主節點實際上不能投票。

因此為了能夠在故障發生時順利選出從節點,集群中至少需要 3 個主節點(且部署在不同的物理機上)。

故障轉移時間:從主節點故障發生到完成轉移,所需要的時間主要消耗在主觀下線識別、主觀下線傳播、選舉延遲等幾個環節。

具體時間與參數 cluster-node-timeout 有關,一般來說:

故障轉移時間(毫秒) ≤1.5 * cluster-node-timeout + 1000。

cluster-node-timeout 的默認值為 15000ms(15 s),因此故障轉移時間會在 20s 量級。

集群的限制及應對方法

由于集群中的數據分布在不同節點中,導致一些功能受限,包括:

key 批量操作受限:例如 mget、mset 操作,只有當操作的 key 都位于一個槽時,才能進行。

針對該問題,一種思路是在客戶端記錄槽與 key 的信息,每次針對特定槽執行 mget/mset;另外一種思路是使用 Hash Tag。

keys/flushall 等操作:keys/flushall 等操作可以在任一節點執行,但是結果只針對當前節點,例如 keys 操作只返回當前節點的所有鍵。

針對該問題,可以在客戶端使用 cluster nodes 獲取所有節點信息,并對其中的所有主節點執行 keys/flushall 等操作。

事務/Lua 腳本:集群支持事務及 Lua 腳本,但前提條件是所涉及的 key 必須在同一個節點。Hash Tag 可以解決該問題。

數據庫:單機 Redis 節點可以支持 16 個數據庫,集群模式下只支持一個,即 db0。

復制結構:只支持一層復制結構,不支持嵌套。

Hash Tag

Hash Tag 原理是:當一個 key 包含 {} 的時候,不對整個 key 做 hash,而僅對 {} 包括的字符串做 hash。

Hash Tag 可以讓不同的 key 擁有相同的 hash 值,從而分配在同一個槽里;這樣針對不同 key 的批量操作(mget/mset 等),以及事務、Lua 腳本等都可以支持。

不過 Hash Tag 可能會帶來數據分配不均的問題,這時需要:

調整不同節點中槽的數量,使數據分布盡量均勻。

避免對熱點數據使用 Hash Tag,導致請求分布不均。

下面是使用 Hash Tag 的一個例子:通過對 product 加 Hash Tag,可以將所有產品信息放到同一個槽中,便于操作。

參數優化

cluster_node_timeout

cluster_node_timeout 參數在前面已經初步介紹;它的默認值是 15s,影響包括:

影響 PING 消息接收節點的選擇:值越大對延遲容忍度越高,選擇的接收節點越少,可以降低帶寬,但會降低收斂速度;應根據帶寬情況和應用要求進行調整。

影響故障轉移的判定和時間:值越大,越不容易誤判,但完成轉移消耗時間越長;應根據網絡狀況和應用要求進行調整。

cluster-require-full-coverage

前面提到,只有當 16384 個槽全部分配完畢時,集群才能上線。這樣做是為了保證集群的完整性。

但同時也帶來了新的問題:當主節點發生故障而故障轉移尚未完成,原主節點中的槽不在任何節點中,此時集群會處于下線狀態,無法響應客戶端的請求。

cluster-require-full-coverage 參數可以改變這一設定:如果設置為 no,則當槽沒有完全分配時,集群仍可以上線。

參數默認值為 yes,如果應用對可用性要求較高,可以修改為 no,但需要自己保證槽全部分配。

redis-trib.rb

redis-trib.rb 提供了眾多實用工具:創建集群、增減節點、槽遷移、檢查完整性、數據重新平衡等;通過 help 命令可以查看詳細信息。

在實踐中如果能使用 redis-trib.rb 工具則盡量使用,不但方便快捷,還可以大大降低出錯概率。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據
    +關注

    關注

    8

    文章

    7002

    瀏覽量

    88943
  • 服務器
    +關注

    關注

    12

    文章

    9123

    瀏覽量

    85331
  • 集群
    +關注

    關注

    0

    文章

    86

    瀏覽量

    17173

原文標題:深入學習 Redis(5):集群

文章出處:【微信號:DBDevs,微信公眾號:數據分析與開發】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Hadoop的集群環境部署說明

    Hadoop集群環境搭建是很多學習hadoop學習者或者是使用者都必然要面對的一個問題,網上關于hadoop集群環境搭建的博文教程也蠻多的。對于玩hadoop的高手來說肯定沒有什么問題
    發表于 10-12 15:51

    kafka架構與集群搭建

    kafka入門+集群搭建
    發表于 04-29 17:06

    3分鐘搭建Redis Cluster集群

    Redis Cluster集群快速搭建
    發表于 06-12 14:58

    Linux的集群搭建方法

    集群(cluster)技術是一種較新的技術,通過集群技術,可以在付出較低成本的情況下獲得在性能、可靠性、靈活性方面的相對較高的收益,其任務調度則是集群系統中的核心技術。
    發表于 07-16 07:46

    zookeeper集群搭建流程概述

    基于docker的zookeeper集群搭建
    發表于 07-23 17:14

    Firefly集群服務器解決方案

    運作,最高可支持11塊核心板,可穩定運行Android、Linux系統,實現統一調試、統一燒錄固件,支持7x24小時無休工作。方案搭建Firefly集群底板+核心板 方案特點多塊核心板
    發表于 08-16 15:09

    搭建Zookeeper集群筆記

    Zookeeper集群搭建
    發表于 09-19 09:01

    Hadoop集群偽分布式的搭建步驟

    Hadoop集群偽分布式搭建
    發表于 11-04 09:19

    hadoop集群搭建的準備

    hadoop集群搭建系列(step01:集群搭建準備)
    發表于 03-31 09:47

    Python虛擬環境的作用搭建方法

    Python虛擬環境的作用搭建方法
    發表于 06-08 07:32

    Kafka集群環境的搭建

    1、環境版本版本:kafka2.11,zookeeper3.4注意:這里zookeeper3.4也是基于集群模式部署。2、解壓重命名tar -zxvf
    發表于 01-05 17:55

    分享一款不錯的采用FPGA的集群通信移動終端設計方案

    分享一款不錯的采用FPGA的集群通信移動終端設計方案
    發表于 05-25 06:32

    Eureka的集群搭建方法-保證高可用

    在微服務架構中,注冊中心是一個必不可少的組件 前面我們搭建的注冊中心只適合本地開發使用,在生產環境必須搭建一個集群來保證高可用 Eureka的集群
    發表于 11-29 10:41 ?7550次閱讀
    Eureka的<b class='flag-5'>集群</b><b class='flag-5'>搭建</b><b class='flag-5'>方法</b>-保證高可用

    虛擬機:Hadoop集群搭建

    虛擬機:Hadoop集群搭建
    的頭像 發表于 07-01 13:03 ?3199次閱讀
    虛擬機:Hadoop<b class='flag-5'>集群</b>的<b class='flag-5'>搭建</b>

    在樹莓派上搭建Kubernetes智能邊緣集群

    電子發燒友網站提供《在樹莓派上搭建Kubernetes智能邊緣集群.zip》資料免費下載
    發表于 12-09 09:20 ?2次下載
    在樹莓派上<b class='flag-5'>搭建</b>Kubernetes智能邊緣<b class='flag-5'>集群</b>
    主站蜘蛛池模板: 51xx午夜影视福利| 父亲在线日本综艺免费观看全集| 国产精品久久高潮呻吟无码| 久久伊人影视| 午夜婷婷一夜七次郎| 99热婷婷国产精品综合| 精品无码日本蜜桃麻豆| 三级在线网址| 6 10young俄罗斯| 解开白丝老师的短裙猛烈进入| 日韩欧美一级| 99久久中文字幕伊人情人| 九九久久精品| 性生片30分钟| 国产成A人片在线观看| 欧美白人极品性喷潮| 中国农村妇女真实BBWBBWBBW| 国产欧美国产综合第一区| 日韩午夜欧美精品一二三四区| 99爱在线精品视频免费观看9| 久久精品视频免费| 黄片a级毛片| 双性被疯狂灌满精NP| 成人毛片100部免费看| 欧美激情精品久久久久久不卡 | 亚洲 小说 欧美 激情 另类| 把腿张开再深点好爽宝贝 | 久久黄视频| 亚洲乱码国产一区三区| 中文字幕乱偷无码AV蜜桃| 国产在线精彩亚洲久久| 甜性涩爱bt下载| 99er热精品视频国产免费| 久久久擼擼擼麻豆| 亚洲这里只有精品| 国产在线精品亚洲一品区| 午夜深情在线观看免费| 国产99精品在线观看| 日韩欧美精品有码在线播放| 成 人 网 站免费观看| 青娱乐极品视觉盛宴av|