0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

集群的作用及搭建方法及設(shè)計(jì)方案

電子工程師 ? 來(lái)源:lq ? 2019-01-15 16:43 ? 次閱讀

在前面的文章中已經(jīng)介紹了 Redis 的幾種高可用技術(shù):持久化、主從復(fù)制和哨兵,但這些方案仍有不足,其中最主要的問(wèn)題是存儲(chǔ)能力受單機(jī)限制,以及無(wú)法實(shí)現(xiàn)寫(xiě)操作的負(fù)載均衡。

本文將詳細(xì)介紹集群,主要內(nèi)容包括:

集群的作用

集群的搭建方法及設(shè)計(jì)方案

集群的基本原理

客戶端訪問(wèn)集群的方法

實(shí)踐須知(集群伸縮、故障轉(zhuǎn)移、參數(shù)優(yōu)化等)

集群的作用

集群,即 Redis Cluster,是 Redis 3.0 開(kāi)始引入的分布式存儲(chǔ)方案。集群由多個(gè)節(jié)點(diǎn)(Node)組成,Redis 的數(shù)據(jù)分布在這些節(jié)點(diǎn)中。

集群中的節(jié)點(diǎn)分為主節(jié)點(diǎn)和從節(jié)點(diǎn):只有主節(jié)點(diǎn)負(fù)責(zé)讀寫(xiě)請(qǐng)求和集群信息的維護(hù);從節(jié)點(diǎn)只進(jìn)行主節(jié)點(diǎn)數(shù)據(jù)和狀態(tài)信息的復(fù)制。

集群的作用,可以歸納為兩點(diǎn):

數(shù)據(jù)分區(qū)

數(shù)據(jù)分區(qū)(或稱數(shù)據(jù)分片)是集群最核心的功能。集群將數(shù)據(jù)分散到多個(gè)節(jié)點(diǎn):

一方面突破了 Redis 單機(jī)內(nèi)存大小的限制,存儲(chǔ)容量大大增加。

另一方面每個(gè)主節(jié)點(diǎn)都可以對(duì)外提供讀服務(wù)和寫(xiě)服務(wù),大大提高了集群的響應(yīng)能力。

Redis 單機(jī)內(nèi)存大小受限問(wèn)題,在介紹持久化和主從復(fù)制時(shí)都有提及。

例如,如果單機(jī)內(nèi)存太大,bgsave 和 bgrewriteaof 的 fork 操作可能導(dǎo)致主進(jìn)程阻塞,主從環(huán)境下主機(jī)切換時(shí)可能導(dǎo)致從節(jié)點(diǎn)長(zhǎng)時(shí)間無(wú)法提供服務(wù),全量復(fù)制階段主節(jié)點(diǎn)的復(fù)制緩沖區(qū)可能溢出。

高可用

集群支持主從復(fù)制和主節(jié)點(diǎn)的自動(dòng)故障轉(zhuǎn)移(與哨兵類似),當(dāng)任一節(jié)點(diǎn)發(fā)生故障時(shí),集群仍然可以對(duì)外提供服務(wù)。本文內(nèi)容基于 Redis 3.0.6。

集群的搭建

我們將搭建一個(gè)簡(jiǎn)單的集群:共 6 個(gè)節(jié)點(diǎn),3 主 3 從。方便起見(jiàn),所有節(jié)點(diǎn)在同一臺(tái)服務(wù)器上,以端口號(hào)進(jìn)行區(qū)分,配置從簡(jiǎn)。

3個(gè)主節(jié)點(diǎn)端口號(hào):7000/7001/7002;對(duì)應(yīng)的從節(jié)點(diǎn)端口號(hào):8000/8001/8002。

集群的搭建有兩種方式:

手動(dòng)執(zhí)行 Redis 命令,一步步完成搭建

使用 Ruby 腳本搭建

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

執(zhí)行 Redis 命令搭建集群

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

啟動(dòng)節(jié)點(diǎn):將節(jié)點(diǎn)以集群模式啟動(dòng),此時(shí)節(jié)點(diǎn)是獨(dú)立的,并沒(méi)有建立聯(lián)系。

節(jié)點(diǎn)握手:讓獨(dú)立的節(jié)點(diǎn)連成一個(gè)網(wǎng)絡(luò)。

分配槽:將 16384 個(gè)槽分配給主節(jié)點(diǎn)。

指定主從關(guān)系:為從節(jié)點(diǎn)指定主節(jié)點(diǎn)。

實(shí)際上,前三步完成后集群便可以對(duì)外提供服務(wù);但指定從節(jié)點(diǎn)后,集群才能夠提供真正高可用的服務(wù)。

啟動(dòng)節(jié)點(diǎn)

集群節(jié)點(diǎn)的啟動(dòng)仍然是使用 redis-server 命令,但需要使用集群模式啟動(dòng)。

下面是 7000 節(jié)點(diǎn)的配置文件(只列出了節(jié)點(diǎn)正常工作關(guān)鍵配置,其他配置,如開(kāi)啟 AOF,可以參照單機(jī)節(jié)點(diǎn)進(jìn)行):

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

其中的 cluster-enabled 和 cluster-config-file 是與集群相關(guān)的配置。

cluster-enabledyes:Redis 實(shí)例可以分為單機(jī)模式(standalone)和集群模式(cluster);cluster-enabledyes 可以啟動(dòng)集群模式。

在單機(jī)模式下啟動(dòng)的 Redis 實(shí)例,如果執(zhí)行 info server 命令,可以發(fā)現(xiàn) redis_mode 一項(xiàng)為 standalone,如下圖所示:

集群模式下的節(jié)點(diǎn),其 redis_mode 為 cluster,如下圖所示:

cluster-config-file:該參數(shù)指定了集群配置文件的位置。每個(gè)節(jié)點(diǎn)在運(yùn)行過(guò)程中,會(huì)維護(hù)一份集群配置文件。

每當(dāng)集群信息發(fā)生變化時(shí)(如增減節(jié)點(diǎn)),集群內(nèi)所有節(jié)點(diǎn)會(huì)將最新信息更新到該配置文件。

當(dāng)節(jié)點(diǎn)重啟后,會(huì)重新讀取該配置文件,獲取集群信息,可以方便的重新加入到集群中。

也就是說(shuō),當(dāng) Redis 節(jié)點(diǎn)以集群模式啟動(dòng)時(shí),會(huì)首先尋找是否有集群配置文件。

如果有則使用文件中的配置啟動(dòng);如果沒(méi)有,則初始化配置并將配置保存到文件中。集群配置文件由 Redis 節(jié)點(diǎn)維護(hù),不需要人工修改。

編輯好配置文件后,使用 redis-server 命令啟動(dòng)該節(jié)點(diǎn):

redis-serverredis-7000.conf

節(jié)點(diǎn)啟動(dòng)以后,通過(guò) cluster nodes 命令可以查看節(jié)點(diǎn)的情況,如下圖所示:

其中返回值第一項(xiàng)表示節(jié)點(diǎn) id,由 40 個(gè) 16 進(jìn)制字符串組成,節(jié)點(diǎn) id 與主從復(fù)制一文中提到的 runId 不同。

Redis 每次啟動(dòng) runId 都會(huì)重新創(chuàng)建,但是節(jié)點(diǎn) id 只在集群初始化時(shí)創(chuàng)建一次,然后保存到集群配置文件中,以后節(jié)點(diǎn)重新啟動(dòng)時(shí)會(huì)直接在集群配置文件中讀取。

其他節(jié)點(diǎn)使用相同辦法啟動(dòng),不再贅述。需要特別注意,在啟動(dòng)節(jié)點(diǎn)階段,節(jié)點(diǎn)是沒(méi)有主從關(guān)系的,因此從節(jié)點(diǎn)不需要加 slaveof 配置。

節(jié)點(diǎn)握手

節(jié)點(diǎn)啟動(dòng)以后是相互獨(dú)立的,并不知道其他節(jié)點(diǎn)存在;需要進(jìn)行節(jié)點(diǎn)握手,將獨(dú)立的節(jié)點(diǎn)組成一個(gè)網(wǎng)絡(luò)。

節(jié)點(diǎn)握手使用 cluster meet {ip} {port} 命令實(shí)現(xiàn),例如在 7000 節(jié)點(diǎn)中執(zhí)行 clustermeet 192.168.72.128 7001,可以完成 7000 節(jié)點(diǎn)和 7001 節(jié)點(diǎn)的握手。

注意:ip 使用的是局域網(wǎng) ip,而不是 localhost 或 127.0.0.1,是為了其他機(jī)器上的節(jié)點(diǎn)或客戶端也可以訪問(wèn)。

此時(shí)再使用 cluster nodes 查看:

在 7001 節(jié)點(diǎn)下也可以類似查看:

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

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

執(zhí)行完上述命令后,可以看到 7000 節(jié)點(diǎn)已經(jīng)感知到了所有其他節(jié)點(diǎn):

通過(guò)節(jié)點(diǎn)之間的通信,每個(gè)節(jié)點(diǎn)都可以感知到所有其他節(jié)點(diǎn),以 8000 節(jié)點(diǎn)為例:

分配槽

在 Redis 集群中,借助槽實(shí)現(xiàn)數(shù)據(jù)分區(qū),具體原理后文會(huì)介紹。集群有 16384 個(gè)槽,槽是數(shù)據(jù)管理和遷移的基本單位。

當(dāng)數(shù)據(jù)庫(kù)中的 16384 個(gè)槽都分配了節(jié)點(diǎn)時(shí),集群處于上線狀態(tài)(ok);如果有任意一個(gè)槽沒(méi)有分配節(jié)點(diǎn),則集群處于下線狀態(tài)(fail)。

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

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

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

此時(shí)查看集群狀態(tài),顯示所有槽分配完畢,集群進(jìn)入上線狀態(tài):

指定主從關(guān)系

集群中指定主從關(guān)系不再使用 slaveof 命令,而是使用 cluster replicate 命令;參數(shù)使用節(jié)點(diǎn) id。

通過(guò) cluster nodes 獲得幾個(gè)主節(jié)點(diǎn)的節(jié)點(diǎn) id 后,執(zhí)行下面的命令為每個(gè)從節(jié)點(diǎn)指定主節(jié)點(diǎn):

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

此時(shí)執(zhí)行 cluster nodes 查看各個(gè)節(jié)點(diǎn)的狀態(tài),可以看到主從關(guān)系已經(jīng)建立:

至此,集群搭建完畢。

使用 Ruby 腳本搭建集群

在 {REDIS_HOME}/src 目錄下可以看到 redis-trib.rb 文件,這是一個(gè) Ruby 腳本,可以實(shí)現(xiàn)自動(dòng)化的集群搭建。

①安裝 Ruby 環(huán)境

以 Ubuntu 為例,如下操作即可安裝 Ruby 環(huán)境:

apt-get install ruby # 安裝 Ruby 環(huán)境。

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

②啟動(dòng)節(jié)點(diǎn)

與第一種方法中的“啟動(dòng)節(jié)點(diǎn)”完全相同。

③搭建集群

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 表示每個(gè)主節(jié)點(diǎn)有 1 個(gè)從節(jié)點(diǎn);后面的多個(gè) {ip:port} 表示節(jié)點(diǎn)地址,前面的做主節(jié)點(diǎn),后面的做從節(jié)點(diǎn)。使用 redis-trib.rb 搭建集群時(shí),要求節(jié)點(diǎn)不能包含任何槽和數(shù)據(jù)。

執(zhí)行創(chuàng)建命令后,腳本會(huì)給出創(chuàng)建集群的計(jì)劃,如下圖所示;計(jì)劃包括哪些是主節(jié)點(diǎn),哪些是從節(jié)點(diǎn),以及如何分配槽。

輸入 yes 確認(rèn)執(zhí)行計(jì)劃,腳本便開(kāi)始按照計(jì)劃執(zhí)行,如下圖所示:

至此,集群搭建完畢。

集群方案設(shè)計(jì)

設(shè)計(jì)集群方案時(shí),至少要考慮以下因素:

高可用要求:根據(jù)故障轉(zhuǎn)移的原理,至少需要 3 個(gè)主節(jié)點(diǎn)才能完成故障轉(zhuǎn)移,且 3 個(gè)主節(jié)點(diǎn)不應(yīng)在同一臺(tái)物理機(jī)上。

每個(gè)主節(jié)點(diǎn)至少需要 1 個(gè)從節(jié)點(diǎn),且主從節(jié)點(diǎn)不應(yīng)在一臺(tái)物理機(jī)上;因此高可用集群至少包含 6 個(gè)節(jié)點(diǎn)。

數(shù)據(jù)量和訪問(wèn)量:估算應(yīng)用需要的數(shù)據(jù)量和總訪問(wèn)量(考慮業(yè)務(wù)發(fā)展,留有冗余),結(jié)合每個(gè)主節(jié)點(diǎn)的容量和能承受的訪問(wèn)量(可以通過(guò) benchmark 得到較準(zhǔn)確估計(jì)),計(jì)算需要的主節(jié)點(diǎn)數(shù)量。

節(jié)點(diǎn)數(shù)量限制:Redis 官方給出的節(jié)點(diǎn)數(shù)量限制為 1000,主要是考慮節(jié)點(diǎn)間通信帶來(lái)的消耗。

在實(shí)際應(yīng)用中應(yīng)盡量避免大集群,如果節(jié)點(diǎn)數(shù)量不足以滿足應(yīng)用對(duì) Redis 數(shù)據(jù)量和訪問(wèn)量的要求,可以考慮:①業(yè)務(wù)分割,大集群分為多個(gè)小集群;②減少不必要的數(shù)據(jù);③調(diào)整數(shù)據(jù)過(guò)期策略等。

適度冗余:Redis 可以在不影響集群服務(wù)的情況下增加節(jié)點(diǎn),因此節(jié)點(diǎn)數(shù)量適當(dāng)冗余即可,不用太大。

集群的基本原理

上面介紹了集群的搭建方法和設(shè)計(jì)方案,下面將進(jìn)一步深入,介紹集群的原理。

集群最核心的功能是數(shù)據(jù)分區(qū),因此:

首先介紹數(shù)據(jù)的分區(qū)規(guī)則。

然后介紹集群實(shí)現(xiàn)的細(xì)節(jié):通信機(jī)制和數(shù)據(jù)結(jié)構(gòu)。

最后以 cluster meet(節(jié)點(diǎn)握手)、cluster addslots(槽分配)為例,說(shuō)明節(jié)點(diǎn)是如何利用上述數(shù)據(jù)結(jié)構(gòu)和通信機(jī)制實(shí)現(xiàn)集群命令的。

數(shù)據(jù)分區(qū)方案

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

哈希分區(qū)的基本思路是:對(duì)數(shù)據(jù)的特征值(如 key)進(jìn)行哈希,然后根據(jù)哈希值決定數(shù)據(jù)落在哪個(gè)節(jié)點(diǎn)。

常見(jiàn)的哈希分區(qū)包括:哈希取余分區(qū)、一致性哈希分區(qū)、帶虛擬節(jié)點(diǎn)的一致性哈希分區(qū)等。

衡量數(shù)據(jù)分區(qū)方法好壞的標(biāo)準(zhǔn)有很多,其中比較重要的兩個(gè)因素是:

數(shù)據(jù)分布是否均勻。

增加或刪減節(jié)點(diǎn)對(duì)數(shù)據(jù)分布的影響。

由于哈希的隨機(jī)性,哈希分區(qū)基本可以保證數(shù)據(jù)分布均勻;因此在比較哈希分區(qū)方案時(shí),重點(diǎn)要看增減節(jié)點(diǎn)對(duì)數(shù)據(jù)分布的影響。

哈希取余分區(qū)

哈希取余分區(qū)思路非常簡(jiǎn)單:計(jì)算 key 的 hash 值,然后對(duì)節(jié)點(diǎn)數(shù)量進(jìn)行取余,從而決定數(shù)據(jù)映射到哪個(gè)節(jié)點(diǎn)上。

該方案最大的問(wèn)題是,當(dāng)新增或刪減節(jié)點(diǎn)時(shí),節(jié)點(diǎn)數(shù)量發(fā)生變化,系統(tǒng)中所有的數(shù)據(jù)都需要重新計(jì)算映射關(guān)系,引發(fā)大規(guī)模數(shù)據(jù)遷移。

一致性哈希分區(qū)

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

對(duì)于每個(gè)數(shù)據(jù),根據(jù) key 計(jì)算 hash 值,確定數(shù)據(jù)在環(huán)上的位置,然后從此位置沿環(huán)順時(shí)針行走,找到的第一臺(tái)服務(wù)器就是其應(yīng)該映射到的服務(wù)器。

與哈希取余分區(qū)相比,一致性哈希分區(qū)將增減節(jié)點(diǎn)的影響限制在相鄰節(jié)點(diǎn)。

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

一致性哈希分區(qū)的主要問(wèn)題在于,當(dāng)節(jié)點(diǎn)數(shù)量較少時(shí),增加或刪減節(jié)點(diǎn),對(duì)單個(gè)節(jié)點(diǎn)的影響可能很大,造成數(shù)據(jù)的嚴(yán)重不平衡。

還是以上圖為例,如果去掉 node2,node4 中的數(shù)據(jù)由總數(shù)據(jù)的 1/4 左右變?yōu)?1/2 左右,與其他節(jié)點(diǎn)相比負(fù)載過(guò)高。

帶虛擬節(jié)點(diǎn)的一致性哈希分區(qū)

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

槽是介于數(shù)據(jù)和實(shí)際節(jié)點(diǎn)之間的虛擬概念;每個(gè)實(shí)際節(jié)點(diǎn)包含一定數(shù)量的槽,每個(gè)槽包含哈希值在一定范圍內(nèi)的數(shù)據(jù)。

引入槽以后,數(shù)據(jù)的映射關(guān)系由數(shù)據(jù) hash->實(shí)際節(jié)點(diǎn),變成了數(shù)據(jù) hash->槽->實(shí)際節(jié)點(diǎn)。

在使用了槽的一致性哈希分區(qū)中,槽是數(shù)據(jù)管理和遷移的基本單位。槽解耦了數(shù)據(jù)和實(shí)際節(jié)點(diǎn)之間的關(guān)系,增加或刪除節(jié)點(diǎn)對(duì)系統(tǒng)的影響很小。

仍以上圖為例,系統(tǒng)中有 4 個(gè)實(shí)際節(jié)點(diǎn),假設(shè)為其分配 16 個(gè)槽(0-15);槽 0-3 位于 node1,4-7 位于 node2,以此類推。

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

槽的數(shù)量一般遠(yuǎn)小于 2^32,遠(yuǎn)大于實(shí)際節(jié)點(diǎn)的數(shù)量;在 Redis 集群中,槽的數(shù)量為 16384。

上面這張圖很好的總結(jié)了 Redis 集群將數(shù)據(jù)映射到實(shí)際節(jié)點(diǎn)的過(guò)程:

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

根據(jù)哈希值,計(jì)算數(shù)據(jù)屬于哪個(gè)槽。

根據(jù)槽與節(jié)點(diǎn)的映射關(guān)系,計(jì)算數(shù)據(jù)屬于哪個(gè)節(jié)點(diǎn)。

節(jié)點(diǎn)通信機(jī)制

集群要作為一個(gè)整體工作,離不開(kāi)節(jié)點(diǎn)之間的通信。

兩個(gè)端口

在哨兵系統(tǒng)中,節(jié)點(diǎn)分為數(shù)據(jù)節(jié)點(diǎn)和哨兵節(jié)點(diǎn):前者存儲(chǔ)數(shù)據(jù),后者實(shí)現(xiàn)額外的控制功能。

在集群中,沒(méi)有數(shù)據(jù)節(jié)點(diǎn)與非數(shù)據(jù)節(jié)點(diǎn)之分:所有的節(jié)點(diǎn)都存儲(chǔ)數(shù)據(jù),也都參與集群狀態(tài)的維護(hù)。

為此,集群中的每個(gè)節(jié)點(diǎn),都提供了兩個(gè) TCP 端口:

普通端口:即我們?cè)谇懊嬷付ǖ亩丝?7000 等)。普通端口主要用于為客戶端提供服務(wù)(與單機(jī)節(jié)點(diǎn)類似);但在節(jié)點(diǎn)間數(shù)據(jù)遷移時(shí)也會(huì)使用。

集群端口:端口號(hào)是普通端口+10000(10000 是固定值,無(wú)法改變),如 7000 節(jié)點(diǎn)的集群端口為 17000。

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

Gossip 協(xié)議

節(jié)點(diǎn)間通信,按照通信協(xié)議可以分為幾種類型:?jiǎn)螌?duì)單、廣播、Gossip 協(xié)議等。重點(diǎn)是廣播和 Gossip 的對(duì)比。

廣播是指向集群內(nèi)所有節(jié)點(diǎn)發(fā)送消息;優(yōu)點(diǎn)是集群的收斂速度快(集群收斂是指集群內(nèi)所有節(jié)點(diǎn)獲得的集群信息是一致的),缺點(diǎn)是每條消息都要發(fā)送給所有節(jié)點(diǎn),CPU、帶寬等消耗較大。

Gossip 協(xié)議的特點(diǎn)是:在節(jié)點(diǎn)數(shù)量有限的網(wǎng)絡(luò)中,每個(gè)節(jié)點(diǎn)都“隨機(jī)”的與部分節(jié)點(diǎn)通信(并不是真正的隨機(jī),而是根據(jù)特定的規(guī)則選擇通信的節(jié)點(diǎn)),經(jīng)過(guò)一番雜亂無(wú)章的通信,每個(gè)節(jié)點(diǎn)的狀態(tài)很快會(huì)達(dá)到一致。

Gossip 協(xié)議的優(yōu)點(diǎn)有負(fù)載(比廣播)低、去中心化、容錯(cuò)性高(因?yàn)橥ㄐ庞腥哂?等;缺點(diǎn)主要是集群的收斂速度慢。

消息類型

集群中的節(jié)點(diǎn)采用固定頻率(每秒 10 次)的定時(shí)任務(wù)進(jìn)行通信相關(guān)的工作:判斷是否需要發(fā)送消息及消息類型、確定接收節(jié)點(diǎn)、發(fā)送消息等。

如果集群狀態(tài)發(fā)生了變化,如增減節(jié)點(diǎn)、槽狀態(tài)變更,通過(guò)節(jié)點(diǎn)間的通信,所有節(jié)點(diǎn)會(huì)很快得知整個(gè)集群的狀態(tài),使集群收斂。

節(jié)點(diǎn)間發(fā)送的消息主要分為 5 種:

MEET 消息

PING 消息

PONG 消息

FAIL 消息

PUBLISH 消息

不同的消息類型,通信協(xié)議、發(fā)送的頻率和時(shí)機(jī)、接收節(jié)點(diǎn)的選擇等是不同的:

MEET 消息:在節(jié)點(diǎn)握手階段,當(dāng)節(jié)點(diǎn)收到客戶端的 cluster meet 命令時(shí),會(huì)向新加入的節(jié)點(diǎn)發(fā)送 MEET 消息,請(qǐng)求新節(jié)點(diǎn)加入到當(dāng)前集群;新節(jié)點(diǎn)收到 MEET 消息后會(huì)回復(fù)一個(gè) PONG 消息。

PING 消息:集群里每個(gè)節(jié)點(diǎn)每秒鐘會(huì)選擇部分節(jié)點(diǎn)發(fā)送 PING 消息,接收者收到消息后會(huì)回復(fù)一個(gè) PONG 消息。PING 消息的內(nèi)容是自身節(jié)點(diǎn)和部分其他節(jié)點(diǎn)的狀態(tài)信息;作用是彼此交換信息,以及檢測(cè)節(jié)點(diǎn)是否在線。

PING 消息使用 Gossip 協(xié)議發(fā)送,接收節(jié)點(diǎn)的選擇兼顧了收斂速度和帶寬成本,具體規(guī)則如下:①隨機(jī)找 5 個(gè)節(jié)點(diǎn),在其中選擇最久沒(méi)有通信的 1 個(gè)節(jié)點(diǎn)。②掃描節(jié)點(diǎn)列表,選擇最近一次收到 PONG 消息時(shí)間大于 cluster_node_timeout/2 的所有節(jié)點(diǎn),防止這些節(jié)點(diǎn)長(zhǎng)時(shí)間未更新。

PONG 消息:PONG 消息封裝了自身狀態(tài)數(shù)據(jù)。可以分為兩種:第一種是在接到 MEET/PING 消息后回復(fù)的 PONG 消息;第二種是指節(jié)點(diǎn)向集群廣播 PONG 消息。

這樣其他節(jié)點(diǎn)可以獲知該節(jié)點(diǎn)的最新信息,例如故障恢復(fù)后新的主節(jié)點(diǎn)會(huì)廣播 PONG 消息。

FAIL 消息:當(dāng)一個(gè)主節(jié)點(diǎn)判斷另一個(gè)主節(jié)點(diǎn)進(jìn)入 FAIL 狀態(tài)時(shí),會(huì)向集群廣播這一 FAIL 消息;接收節(jié)點(diǎn)會(huì)將這一 FAIL 消息保存起來(lái),便于后續(xù)的判斷。

PUBLISH 消息:節(jié)點(diǎn)收到 PUBLISH 命令后,會(huì)先執(zhí)行該命令,然后向集群廣播這一消息,接收節(jié)點(diǎn)也會(huì)執(zhí)行該 PUBLISH 命令。

數(shù)據(jù)結(jié)構(gòu)

節(jié)點(diǎn)需要專門(mén)的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)集群的狀態(tài)。所謂集群的狀態(tài),是一個(gè)比較大的概念,包括:集群是否處于上線狀態(tài)、集群中有哪些節(jié)點(diǎn)、節(jié)點(diǎn)是否可達(dá)、節(jié)點(diǎn)的主從狀態(tài)、槽的分布……

節(jié)點(diǎn)為了存儲(chǔ)集群狀態(tài)而提供的數(shù)據(jù)結(jié)構(gòu)中,最關(guān)鍵的是 clusterNode 和 clusterState 結(jié)構(gòu):前者記錄了一個(gè)節(jié)點(diǎn)的狀態(tài),后者記錄了集群作為一個(gè)整體的狀態(tài)。

clusterNode

clusterNode 結(jié)構(gòu)保存了一個(gè)節(jié)點(diǎn)的當(dāng)前狀態(tài),包括創(chuàng)建時(shí)間、節(jié)點(diǎn) id、ip 和端口號(hào)等。

每個(gè)節(jié)點(diǎn)都會(huì)用一個(gè) clusterNode 結(jié)構(gòu)記錄自己的狀態(tài),并為集群內(nèi)所有其他節(jié)點(diǎn)都創(chuàng)建一個(gè) clusterNode 結(jié)構(gòu)來(lái)記錄節(jié)點(diǎn)狀態(tài)。

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

typedefstructclusterNode{//節(jié)點(diǎn)創(chuàng)建時(shí)間mstime_tctime;//節(jié)點(diǎn)idcharname[REDIS_CLUSTER_NAMELEN];//節(jié)點(diǎn)的ip和端口號(hào)charip[REDIS_IP_STR_LEN];intport;//節(jié)點(diǎn)標(biāo)識(shí):整型,每個(gè)bit都代表了不同狀態(tài),如節(jié)點(diǎn)的主從狀態(tài)、是否在線、是否在握手等intflags;//配置紀(jì)元:故障轉(zhuǎn)移時(shí)起作用,類似于哨兵的配置紀(jì)元uint64_tconfigEpoch;//槽在該節(jié)點(diǎn)中的分布:占用16384/8個(gè)字節(jié),16384個(gè)比特;每個(gè)比特對(duì)應(yīng)一個(gè)槽:比特值為1,則該比特對(duì)應(yīng)的槽在節(jié)點(diǎn)中;比特值為0,則該比特對(duì)應(yīng)的槽不在節(jié)點(diǎn)中unsignedcharslots[16384/8];//節(jié)點(diǎn)中槽的數(shù)量intnumslots;…………}clusterNode;

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

集群命令的實(shí)現(xiàn)

這一部分將以 cluster meet(節(jié)點(diǎn)握手)、cluster addslots(槽分配)為例,說(shuō)明節(jié)點(diǎn)是如何利用上述數(shù)據(jù)結(jié)構(gòu)和通信機(jī)制實(shí)現(xiàn)集群命令的。

cluster meet

假設(shè)要向 A 節(jié)點(diǎn)發(fā)送 cluster meet 命令,將 B 節(jié)點(diǎn)加入到 A 所在的集群,則 A 節(jié)點(diǎn)收到命令后,執(zhí)行的操作如下:

A 為 B 創(chuàng)建一個(gè) clusterNode 結(jié)構(gòu),并將其添加到 clusterState 的 nodes 字典中。

A 向 B 發(fā)送 MEET 消息。

B 收到 MEET 消息后,會(huì)為 A 創(chuàng)建一個(gè) clusterNode 結(jié)構(gòu),并將其添加到 clusterState 的 nodes 字典中。

B 回復(fù) A 一個(gè) PONG 消息。

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

然后,A 向 B 返回一個(gè) PING 消息。

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

之后,A 通過(guò) Gossip 協(xié)議將 B 的信息廣播給集群內(nèi)其他節(jié)點(diǎn),其他節(jié)點(diǎn)也會(huì)與 B 握手;一段時(shí)間后,集群收斂,B 成為集群內(nèi)的一個(gè)普通節(jié)點(diǎn)。

通過(guò)上述過(guò)程可以發(fā)現(xiàn),集群中兩個(gè)節(jié)點(diǎn)的握手過(guò)程與 TCP 類似,都是三次握手:A 向 B 發(fā)送 MEET;B 向 A 發(fā)送 PONG;A 向 B 發(fā)送 PING。

cluster addslots

集群中槽的分配信息,存儲(chǔ)在 clusterNode 的 slots 數(shù)組和 clusterState 的 slots 數(shù)組中,兩個(gè)數(shù)組的結(jié)構(gòu)前面已做介紹。

二者的區(qū)別在于:前者存儲(chǔ)的是該節(jié)點(diǎn)中分配了哪些槽,后者存儲(chǔ)的是集群中所有槽分別分布在哪個(gè)節(jié)點(diǎn)。

cluster addslots 命令接收一個(gè)槽或多個(gè)槽作為參數(shù),例如在 A 節(jié)點(diǎn)上執(zhí)行 cluster addslots {0..10} 命令,是將編號(hào)為 0-10 的槽分配給 A 節(jié)點(diǎn)。

具體執(zhí)行過(guò)程如下:

遍歷輸入槽,檢查它們是否都沒(méi)有分配,如果有一個(gè)槽已分配,命令執(zhí)行失??;方法是檢查輸入槽在 clusterState.slots[] 中對(duì)應(yīng)的值是否為 NULL。

遍歷輸入槽,將其分配給節(jié)點(diǎn) A;方法是修改 clusterNode.slots[] 中對(duì)應(yīng)的比特為 1,以及 clusterState.slots[] 中對(duì)應(yīng)的指針指向 A 節(jié)點(diǎn)。

A 節(jié)點(diǎn)執(zhí)行完成后,通過(guò)節(jié)點(diǎn)通信機(jī)制通知其他節(jié)點(diǎn),所有節(jié)點(diǎn)都會(huì)知道 0-10 的槽分配給了 A 節(jié)點(diǎn)。

客戶端訪問(wèn)集群

在集群中,數(shù)據(jù)分布在不同的節(jié)點(diǎn)中,客戶端通過(guò)某節(jié)點(diǎn)訪問(wèn)數(shù)據(jù)時(shí),數(shù)據(jù)可能不在該節(jié)點(diǎn)中;下面介紹集群是如何處理這個(gè)問(wèn)題的。

redis-cli

當(dāng)節(jié)點(diǎn)收到 redis-cli 發(fā)來(lái)的命令(如 set/get)時(shí),過(guò)程如下:

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

集群提供的 cluster keyslot 命令也是使用上述公式實(shí)現(xiàn),如:

②判斷 key 所在的槽是否在當(dāng)前節(jié)點(diǎn):假設(shè) key 位于第 i 個(gè)槽,clusterState.slots[i] 則指向了槽所在的節(jié)點(diǎn)。

如果 clusterState.slots[i]==clusterState.myself,說(shuō)明槽在當(dāng)前節(jié)點(diǎn),可以直接在當(dāng)前節(jié)點(diǎn)執(zhí)行命令。

否則,說(shuō)明槽不在當(dāng)前節(jié)點(diǎn),則查詢槽所在節(jié)點(diǎn)的地址(clusterState.slots[i].ip/port),并將其包裝到 MOVED 錯(cuò)誤中返回給 redis-cli。

③redis-cli 收到 MOVED 錯(cuò)誤后,根據(jù)返回的 ip 和 port 重新發(fā)送請(qǐng)求。

下面的例子展示了 redis-cli 和集群的互動(dòng)過(guò)程:在 7000 節(jié)點(diǎn)中操作 key1,但 key1 所在的槽 9189 在節(jié)點(diǎn) 7001 中。

因此節(jié)點(diǎn)返回 MOVED 錯(cuò)誤(包含 7001 節(jié)點(diǎn)的 ip 和 port)給 redis-cli,redis-cli 重新向 7001 發(fā)起請(qǐng)求。

上例中,redis-cli 通過(guò) -c 指定了集群模式,如果沒(méi)有指定,redis-cli 無(wú)法處理 MOVED 錯(cuò)誤:

Smart 客戶端

redis-cli 這一類客戶端稱為 Dummy 客戶端,因?yàn)樗鼈冊(cè)趫?zhí)行命令前不知道數(shù)據(jù)在哪個(gè)節(jié)點(diǎn),需要借助 MOVED 錯(cuò)誤重新定向。與 Dummy 客戶端相對(duì)應(yīng)的是 Smart 客戶端。

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

①JedisCluster 初始化時(shí),在內(nèi)部維護(hù) slot->node 的緩存,方法是連接任一節(jié)點(diǎn),執(zhí)行 cluster slots 命令,該命令返回如下所示:

②此外,JedisCluster 為每個(gè)節(jié)點(diǎn)創(chuàng)建連接池(即 JedisPool)。

③當(dāng)執(zhí)行命令時(shí),JedisCluster 根據(jù) key->slot->node 選擇需要連接的節(jié)點(diǎn),發(fā)送命令。

如果成功,則命令執(zhí)行完畢;如果執(zhí)行失敗,則會(huì)隨機(jī)選擇其他節(jié)點(diǎn)進(jìn)行重試,并在出現(xiàn) MOVED 錯(cuò)誤時(shí),使用 cluster slots 重新同步 slot->node 的映射關(guān)系。

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

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();}

注意事項(xiàng)如下:

JedisCluster 中已經(jīng)包含所有節(jié)點(diǎn)的連接池,因此 JedisCluster 要使用單例。

客戶端維護(hù)了 slot->node 映射關(guān)系以及為每個(gè)節(jié)點(diǎn)創(chuàng)建了連接池,當(dāng)節(jié)點(diǎn)數(shù)量較多時(shí),應(yīng)注意客戶端內(nèi)存資源和連接資源的消耗。

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

實(shí)踐須知

前面介紹了集群正常運(yùn)行和訪問(wèn)的方法和原理,下面是一些重要的補(bǔ)充內(nèi)容。

集群伸縮

實(shí)踐中常常需要對(duì)集群進(jìn)行伸縮,如訪問(wèn)量增大時(shí)的擴(kuò)容操作。Redis 集群可以在不影響對(duì)外服務(wù)的情況下實(shí)現(xiàn)伸縮;伸縮的核心是槽遷移:修改槽與節(jié)點(diǎn)的對(duì)應(yīng)關(guān)系,實(shí)現(xiàn)槽(即數(shù)據(jù))在節(jié)點(diǎn)之間的移動(dòng)。

例如,如果槽均勻分布在集群的 3 個(gè)節(jié)點(diǎn)中,此時(shí)增加一個(gè)節(jié)點(diǎn),則需要從 3 個(gè)節(jié)點(diǎn)中分別拿出一部分槽給新節(jié)點(diǎn),從而實(shí)現(xiàn)槽在 4 個(gè)節(jié)點(diǎn)中的均勻分布。

增加節(jié)點(diǎn)

假設(shè)要增加 7003 和 8003 節(jié)點(diǎn),其中 8003 是 7003 的從節(jié)點(diǎn),步驟如下:

①啟動(dòng)節(jié)點(diǎn):方法參見(jiàn)集群搭建。

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

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 工具實(shí)現(xiàn)。reshard 自動(dòng)化程度很高,只需要輸入 redis-trib.rb reshard ip:port (ip 和 port 可以是集群中的任一節(jié)點(diǎn))。

然后按照提示輸入以下信息,槽遷移會(huì)自動(dòng)完成:

待遷移的槽數(shù)量:16384 個(gè)槽均分給 4 個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn) 4096 個(gè)槽,因此待遷移槽數(shù)量為 4096。

目標(biāo)節(jié)點(diǎn) id:7003 節(jié)點(diǎn)的 id。

源節(jié)點(diǎn)的 id:7000/7001/7002 節(jié)點(diǎn)的 id。

④指定主從關(guān)系:方法參見(jiàn)集群搭建。

減少節(jié)點(diǎn)

假設(shè)要下線 7000/8000 節(jié)點(diǎn),可以分為兩步:

遷移槽:使用 reshard 將 7000 節(jié)點(diǎn)中的槽均勻遷移到 7001/7002/7003 節(jié)點(diǎn)。

下線節(jié)點(diǎn):使用 redis-trib.rb del-node 工具;應(yīng)先下線從節(jié)點(diǎn)再下線主節(jié)點(diǎn),因?yàn)槿糁鞴?jié)點(diǎn)先下線,從節(jié)點(diǎn)會(huì)被指向其他主節(jié)點(diǎn),造成不必要的全量復(fù)制。

redis-trib.rbdel-node192.168.72.128:7001{節(jié)點(diǎn)8000的id}redis-trib.rbdel-node192.168.72.128:7001{節(jié)點(diǎn)7000的id}

ASK 錯(cuò)誤

集群伸縮的核心是槽遷移。在槽遷移過(guò)程中,如果客戶端向源節(jié)點(diǎn)發(fā)送命令,源節(jié)點(diǎn)執(zhí)行流程如下:

客戶端收到 ASK 錯(cuò)誤后,從中讀取目標(biāo)節(jié)點(diǎn)的地址信息,并向目標(biāo)節(jié)點(diǎn)重新發(fā)送請(qǐng)求,就像收到 MOVED 錯(cuò)誤時(shí)一樣。

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

故障轉(zhuǎn)移

在哨兵一文中,介紹了哨兵實(shí)現(xiàn)故障發(fā)現(xiàn)和故障轉(zhuǎn)移的原理。

雖然細(xì)節(jié)上有很大不同,但集群的實(shí)現(xiàn)與哨兵思路類似:通過(guò)定時(shí)任務(wù)發(fā)送 PING 消息檢測(cè)其他節(jié)點(diǎn)狀態(tài);節(jié)點(diǎn)下線分為主觀下線和客觀下線;客觀下線后選取從節(jié)點(diǎn)進(jìn)行故障轉(zhuǎn)移。

與哨兵一樣,集群只實(shí)現(xiàn)了主節(jié)點(diǎn)的故障轉(zhuǎn)移;從節(jié)點(diǎn)故障時(shí)只會(huì)被下線,不會(huì)進(jìn)行故障轉(zhuǎn)移。

因此,使用集群時(shí),應(yīng)謹(jǐn)慎使用讀寫(xiě)分離技術(shù),因?yàn)閺墓?jié)點(diǎn)故障會(huì)導(dǎo)致讀服務(wù)不可用,可用性變差。

這里不再詳細(xì)介紹故障轉(zhuǎn)移的細(xì)節(jié),只對(duì)重要事項(xiàng)進(jìn)行說(shuō)明:

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

因此為了能夠在故障發(fā)生時(shí)順利選出從節(jié)點(diǎn),集群中至少需要 3 個(gè)主節(jié)點(diǎn)(且部署在不同的物理機(jī)上)。

故障轉(zhuǎn)移時(shí)間:從主節(jié)點(diǎn)故障發(fā)生到完成轉(zhuǎn)移,所需要的時(shí)間主要消耗在主觀下線識(shí)別、主觀下線傳播、選舉延遲等幾個(gè)環(huán)節(jié)。

具體時(shí)間與參數(shù) cluster-node-timeout 有關(guān),一般來(lái)說(shuō):

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

cluster-node-timeout 的默認(rèn)值為 15000ms(15 s),因此故障轉(zhuǎn)移時(shí)間會(huì)在 20s 量級(jí)。

集群的限制及應(yīng)對(duì)方法

由于集群中的數(shù)據(jù)分布在不同節(jié)點(diǎn)中,導(dǎo)致一些功能受限,包括:

key 批量操作受限:例如 mget、mset 操作,只有當(dāng)操作的 key 都位于一個(gè)槽時(shí),才能進(jìn)行。

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

keys/flushall 等操作:keys/flushall 等操作可以在任一節(jié)點(diǎn)執(zhí)行,但是結(jié)果只針對(duì)當(dāng)前節(jié)點(diǎn),例如 keys 操作只返回當(dāng)前節(jié)點(diǎn)的所有鍵。

針對(duì)該問(wèn)題,可以在客戶端使用 cluster nodes 獲取所有節(jié)點(diǎn)信息,并對(duì)其中的所有主節(jié)點(diǎn)執(zhí)行 keys/flushall 等操作。

事務(wù)/Lua 腳本:集群支持事務(wù)及 Lua 腳本,但前提條件是所涉及的 key 必須在同一個(gè)節(jié)點(diǎn)。Hash Tag 可以解決該問(wèn)題。

數(shù)據(jù)庫(kù):?jiǎn)螜C(jī) Redis 節(jié)點(diǎn)可以支持 16 個(gè)數(shù)據(jù)庫(kù),集群模式下只支持一個(gè),即 db0。

復(fù)制結(jié)構(gòu):只支持一層復(fù)制結(jié)構(gòu),不支持嵌套。

Hash Tag

Hash Tag 原理是:當(dāng)一個(gè) key 包含 {} 的時(shí)候,不對(duì)整個(gè) key 做 hash,而僅對(duì) {} 包括的字符串做 hash。

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

不過(guò) Hash Tag 可能會(huì)帶來(lái)數(shù)據(jù)分配不均的問(wèn)題,這時(shí)需要:

調(diào)整不同節(jié)點(diǎn)中槽的數(shù)量,使數(shù)據(jù)分布盡量均勻。

避免對(duì)熱點(diǎn)數(shù)據(jù)使用 Hash Tag,導(dǎo)致請(qǐng)求分布不均。

下面是使用 Hash Tag 的一個(gè)例子:通過(guò)對(duì) product 加 Hash Tag,可以將所有產(chǎn)品信息放到同一個(gè)槽中,便于操作。

參數(shù)優(yōu)化

cluster_node_timeout

cluster_node_timeout 參數(shù)在前面已經(jīng)初步介紹;它的默認(rèn)值是 15s,影響包括:

影響 PING 消息接收節(jié)點(diǎn)的選擇:值越大對(duì)延遲容忍度越高,選擇的接收節(jié)點(diǎn)越少,可以降低帶寬,但會(huì)降低收斂速度;應(yīng)根據(jù)帶寬情況和應(yīng)用要求進(jìn)行調(diào)整。

影響故障轉(zhuǎn)移的判定和時(shí)間:值越大,越不容易誤判,但完成轉(zhuǎn)移消耗時(shí)間越長(zhǎng);應(yīng)根據(jù)網(wǎng)絡(luò)狀況和應(yīng)用要求進(jìn)行調(diào)整。

cluster-require-full-coverage

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

但同時(shí)也帶來(lái)了新的問(wèn)題:當(dāng)主節(jié)點(diǎn)發(fā)生故障而故障轉(zhuǎn)移尚未完成,原主節(jié)點(diǎn)中的槽不在任何節(jié)點(diǎn)中,此時(shí)集群會(huì)處于下線狀態(tài),無(wú)法響應(yīng)客戶端的請(qǐng)求。

cluster-require-full-coverage 參數(shù)可以改變這一設(shè)定:如果設(shè)置為 no,則當(dāng)槽沒(méi)有完全分配時(shí),集群仍可以上線。

參數(shù)默認(rèn)值為 yes,如果應(yīng)用對(duì)可用性要求較高,可以修改為 no,但需要自己保證槽全部分配。

redis-trib.rb

redis-trib.rb 提供了眾多實(shí)用工具:創(chuàng)建集群、增減節(jié)點(diǎn)、槽遷移、檢查完整性、數(shù)據(jù)重新平衡等;通過(guò) help 命令可以查看詳細(xì)信息。

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

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7067

    瀏覽量

    89116
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    12

    文章

    9204

    瀏覽量

    85548
  • 集群
    +關(guān)注

    關(guān)注

    0

    文章

    86

    瀏覽量

    17179

原文標(biāo)題:深入學(xué)習(xí) Redis(5):集群

文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Hadoop的集群環(huán)境部署說(shuō)明

    Hadoop集群環(huán)境搭建是很多學(xué)習(xí)hadoop學(xué)習(xí)者或者是使用者都必然要面對(duì)的一個(gè)問(wèn)題,網(wǎng)上關(guān)于hadoop集群環(huán)境搭建的博文教程也蠻多的。對(duì)于玩hadoop的高手來(lái)說(shuō)肯定沒(méi)有什么問(wèn)題
    發(fā)表于 10-12 15:51

    kafka架構(gòu)與集群搭建

    kafka入門(mén)+集群搭建
    發(fā)表于 04-29 17:06

    3分鐘搭建Redis Cluster集群

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

    Linux的集群搭建方法

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

    zookeeper集群搭建流程概述

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

    Firefly集群服務(wù)器解決方案

    運(yùn)作,最高可支持11塊核心板,可穩(wěn)定運(yùn)行Android、Linux系統(tǒng),實(shí)現(xiàn)統(tǒng)一調(diào)試、統(tǒng)一燒錄固件,支持7x24小時(shí)無(wú)休工作。方案搭建Firefly集群底板+核心板 方案特點(diǎn)多塊核心板
    發(fā)表于 08-16 15:09

    搭建Zookeeper集群筆記

    Zookeeper集群搭建
    發(fā)表于 09-19 09:01

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

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

    hadoop集群搭建的準(zhǔn)備

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

    Python虛擬環(huán)境的作用搭建方法

    Python虛擬環(huán)境的作用搭建方法
    發(fā)表于 06-08 07:32

    Kafka集群環(huán)境的搭建

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

    分享一款不錯(cuò)的采用FPGA的集群通信移動(dòng)終端設(shè)計(jì)方案

    分享一款不錯(cuò)的采用FPGA的集群通信移動(dòng)終端設(shè)計(jì)方案
    發(fā)表于 05-25 06:32

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

    在微服務(wù)架構(gòu)中,注冊(cè)中心是一個(gè)必不可少的組件 前面我們搭建的注冊(cè)中心只適合本地開(kāi)發(fā)使用,在生產(chǎn)環(huán)境必須搭建一個(gè)集群來(lái)保證高可用 Eureka的集群
    發(fā)表于 11-29 10:41 ?7557次閱讀
    Eureka的<b class='flag-5'>集群</b><b class='flag-5'>搭建</b><b class='flag-5'>方法</b>-保證高可用

    虛擬機(jī):Hadoop集群搭建

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

    在樹(shù)莓派上搭建Kubernetes智能邊緣集群

    電子發(fā)燒友網(wǎng)站提供《在樹(shù)莓派上搭建Kubernetes智能邊緣集群.zip》資料免費(fèi)下載
    發(fā)表于 12-09 09:20 ?2次下載
    在樹(shù)莓派上<b class='flag-5'>搭建</b>Kubernetes智能邊緣<b class='flag-5'>集群</b>