0、引言
? ? ? ? 單機(jī)式Redis存在以下問(wèn)題,因此需要Redis集群化來(lái)解決這些問(wèn)題
1、持久化
1.1 RDB(Redis Database Backup file )持久化
???????Redis數(shù)據(jù)快照,簡(jiǎn)單來(lái)說(shuō)就是把內(nèi)存中的所有數(shù)據(jù)都記錄到磁盤中。當(dāng)Redis實(shí)例故障重啟后,從磁盤讀取快照文件,恢復(fù)數(shù)據(jù)??煺瘴募Q為RDB文件,默認(rèn)是保存在當(dāng)前運(yùn)行目錄。 ??
?(1)執(zhí)行方法:
?(2)原理
? ? ? ? 著重比較一下save命令與bgsave:
? ? ? ? save會(huì)阻塞所有命令,因?yàn)閭浞莸倪^(guò)程不允許更改。
????????而bgsave不會(huì)阻塞其他命令、是通過(guò)fork一個(gè)子線程共享數(shù)據(jù),然后讀取內(nèi)存數(shù)據(jù)并寫入 RDB 文件,如果主線程此時(shí)進(jìn)行寫操作,則會(huì)拷貝一份數(shù)據(jù)出來(lái)執(zhí)行寫操作。
? ? ? ? 個(gè)人理解,這個(gè)Redis的RDB文件類似于Mysql里的Redo日志,存的是數(shù)據(jù)。
1.2 AOF(Append Only File )持久化?
(1)AOF持久化原理
? ? ? ? 與RDB相對(duì)的,AOF并不是直接將數(shù)據(jù)存入磁盤進(jìn)行持久化保存,
????????而是通過(guò)將每一個(gè)寫命令記錄在AOF文件中實(shí)現(xiàn)持久化。個(gè)人理解,就很類似于Mysql的Binlog日志,記錄的是具體的語(yǔ)句操作。
? ? ? ? 例如,set num 123這一步操作,AOF就會(huì)記錄相應(yīng)的操作語(yǔ)句。
? ? ? ? 其刷盤頻率的規(guī)定如下:?通過(guò)redis.conf文件進(jìn)行配置:
# 表示每執(zhí)行一次寫命令,立即記錄到AOF文件
appendfsync always?
# 寫命令執(zhí)行完先放入AOF緩沖區(qū),然后表示每隔1秒將緩沖區(qū)數(shù)據(jù)寫到AOF文件,是默認(rèn)方案
appendfsync everysec?
# 寫命令執(zhí)行完先放入AOF緩沖區(qū),由操作系統(tǒng)決定何時(shí)將緩沖區(qū)內(nèi)容寫回磁盤
appendfsync no
(2)AOF的文件重寫
? ? ? ? 既然記錄的是寫操作,如果對(duì)一個(gè)數(shù)據(jù)多次重復(fù)寫,那么有很多次寫操作都是無(wú)用操作,因此AOF能夠執(zhí)行如圖所示重寫功能:
? ? ? ??
?1.3 RDB與AOF對(duì)比總結(jié)
2、Redis主從架構(gòu)
2.1 簡(jiǎn)單搭建
? ? ? ? 類似于MySQL,單節(jié)點(diǎn)Redis并發(fā)能力有限,需要搭建主從結(jié)構(gòu):即,主Redis進(jìn)行寫操作,從Redis執(zhí)行讀操作,并且主從之間要保持?jǐn)?shù)據(jù)同步。
搭建流程:
連接到從redis:
redis-cli -p 端口號(hào)
建立其master:
SLAVEOF 主IP地址 主端口號(hào)(SLAVEOF也可以換成REPLICAOF)
?2.2 全量同步
(1)基本流程
????????主從第一次建立連接時(shí),會(huì)執(zhí)行全量同步,將master節(jié)點(diǎn)的所有數(shù)據(jù)都拷貝給slave節(jié)點(diǎn)。
????????在同步的過(guò)程中,需要用到上文提到的RDB文件。
? ? ? ? 還會(huì)用到repl_baklog文件:通過(guò)bgsave生成RDB時(shí),是子進(jìn)程復(fù)制出的數(shù)據(jù)進(jìn)行存盤,但如果此時(shí)主線程趁此時(shí)進(jìn)行寫數(shù)據(jù),那這些新的數(shù)據(jù)不就沒有同步進(jìn)slave里了嗎??
? ? ? ? 因此,redis會(huì)在此時(shí)通過(guò)repl_baklog記錄bgsave期間的所有命令,再發(fā)給slave進(jìn)行補(bǔ)充,保證數(shù)據(jù)的完整。
? ? ? ? 具體流程如下:
?(2)問(wèn)題:slave向master請(qǐng)求數(shù)據(jù)同步,master如何知道這是第一次來(lái)連接?
通過(guò)以下兩個(gè)概念作為判斷依據(jù):
Replication Id:簡(jiǎn)稱replid,是數(shù)據(jù)集的標(biāo)記,id一致則說(shuō)明是同一數(shù)據(jù)集。每一個(gè)master都有唯一的replid,slave則會(huì)繼承master節(jié)點(diǎn)的replid
此為關(guān)鍵:這個(gè)id如果不同,說(shuō)明是第一次!offset:偏移量,隨著記錄在repl_baklog中的數(shù)據(jù)增多而逐漸增大。slave完成同步時(shí)也會(huì)記錄當(dāng)前同步的offset。如果slave的offset小于master的offset,說(shuō)明slave數(shù)據(jù)落后于master,需要更新。
?????????因?yàn)閟lave原本也是一個(gè)master,有自己的replid和offset,當(dāng)?shù)谝淮巫兂蓅lave,與master建立連接時(shí),發(fā)送的replid和offset是自己的replid和offset。master判斷發(fā)現(xiàn)slave發(fā)送來(lái)的replid與自己的不一致,說(shuō)明這是一個(gè)全新的slave,就知道要做全量同步了。
????????master會(huì)將自己的replid和offset都發(fā)送給這個(gè)slave,slave保存這些信息。以后slave的replid就與master一致了。
??2.3?增量同步
? ? ? ? 在2.2節(jié)的基礎(chǔ)上,當(dāng)主從的Replication Id相同時(shí),我們可以理解為,此時(shí)slave數(shù)據(jù)集至少是master的子集了。
? ? ? ? 主從數(shù)據(jù)剩余部分具體相差多少呢?可以通過(guò)offset偏移量來(lái)進(jìn)行記錄。
????????repl_baklog中會(huì)記錄Redis處理過(guò)的命令日志及offset,包括master當(dāng)前的offset,和slave已經(jīng)拷貝到的offset。每次在第二階段,master就去發(fā)送:從 已經(jīng)拷貝過(guò)的offset開始 到 當(dāng)前offset的數(shù)據(jù),如圖所示:
? ?---->? ? ??
? ? ? ?---->???
?????????repl_baklog這個(gè)文件是一個(gè)固定大小的數(shù)組,只不過(guò)數(shù)組是環(huán)形,也就是說(shuō)角標(biāo)到達(dá)數(shù)組末尾后,會(huì)再次從0開始讀寫,這樣數(shù)組頭部的數(shù)據(jù)就會(huì)被覆蓋,但因?yàn)閟lave(綠色部分已經(jīng)同步了,因此master可以直接覆蓋也無(wú)妨)
? ? ? ? 但是如果slave宕機(jī)過(guò)久,導(dǎo)致master把尚未同步的紅色部分覆蓋了(即,紅色超過(guò)了一整圈):例如下圖,此時(shí)只能全量同步了。?
?2.4 知識(shí)總結(jié)
簡(jiǎn)述全量同步和增量同步區(qū)別?
全量同步:master將完整內(nèi)存數(shù)據(jù)生成RDB,發(fā)送RDB到slave。后續(xù)命令則記錄在repl_baklog,逐個(gè)發(fā)送給slave。
增量同步:slave提交自己的offset到master,master獲取repl_baklog中從offset之后的命令給slave
什么時(shí)候執(zhí)行全量同步?
slave節(jié)點(diǎn)第一次連接master節(jié)點(diǎn)時(shí)
slave節(jié)點(diǎn)斷開時(shí)間太久,repl_baklog中的offset已經(jīng)被覆蓋時(shí)
什么時(shí)候執(zhí)行增量同步?
slave節(jié)點(diǎn)斷開又恢復(fù),并且在repl_baklog中能找到offset時(shí)
????????RDB 優(yōu)點(diǎn)是數(shù)據(jù)恢復(fù)速度快,但是快照的頻率不好把握。頻率太低,丟失的數(shù)據(jù)就會(huì)比較多,頻率太高,就會(huì)影響性能。
????????AOF 優(yōu)點(diǎn)是丟失數(shù)據(jù)少,但是數(shù)據(jù)恢復(fù)不快。
3、 Redis哨兵
? ? ? ? 在第2節(jié)中,我們講述了從機(jī)宕機(jī)后,通過(guò)repl_baklog的offset來(lái)進(jìn)行恢復(fù)從機(jī)的數(shù)據(jù)。
? ? ? ? 但如果,宕機(jī)是主機(jī)而不是從機(jī),該怎么辦?顯然這時(shí)候需要指定新的主機(jī)了!而redis哨兵機(jī)制能夠自動(dòng)監(jiān)控主機(jī)的健康狀態(tài)、以及在主機(jī)掛掉后指定從機(jī)。
3.1 原理? ? ?
監(jiān)控:Sentinel 會(huì)不斷檢查您的master和slave是否按預(yù)期工作
? ? ? ? 這里sentinel會(huì)反復(fù)向主機(jī)發(fā)送ping,如果在規(guī)定時(shí)間內(nèi)收到pong,說(shuō)明主機(jī)還是好的,反之反之。如果有超過(guò)半數(shù)的哨兵認(rèn)為主機(jī)掛了,那說(shuō)明主機(jī)掛了。自動(dòng)故障恢復(fù):如果master故障,Sentinel會(huì)將一個(gè)slave提升為master。當(dāng)故障實(shí)例恢復(fù)后也以新的master為主
? ? ? ?具體怎么選新的主機(jī)呢?
? ? ? ?首先會(huì)判斷slave節(jié)點(diǎn)與master節(jié)點(diǎn)斷開時(shí)間長(zhǎng)短,如果超過(guò)指定值(down-after-milliseconds * 10)則會(huì)排除該slave節(jié)點(diǎn)
? ? ? ?然后判斷slave節(jié)點(diǎn)的slave-priority值,越小優(yōu)先級(jí)越高,如果是0則永不參與選舉
? ? ? ?如果slave-prority一樣,則判斷slave節(jié)點(diǎn)的offset值,越大說(shuō)明數(shù)據(jù)越新,優(yōu)先級(jí)越高
? ? ? ?最后是判斷slave節(jié)點(diǎn)的運(yùn)行id大小,越小優(yōu)先級(jí)越高通知:Sentinel充當(dāng)Redis客戶端的服務(wù)發(fā)現(xiàn)來(lái)源,當(dāng)集群發(fā)生故障轉(zhuǎn)移時(shí),會(huì)將最新信息推送給Redis的客戶端
3.2 故障轉(zhuǎn)移步驟
故障轉(zhuǎn)移步驟有哪些?
首先選定一個(gè)slave作為新的master,執(zhí)行slaveof no one
然后讓所有節(jié)點(diǎn)都執(zhí)行slaveof 新master
修改故障節(jié)點(diǎn)配置,添加slaveof 新master
4、 Cluster分片集群
? ? ? ? 對(duì)于第3節(jié)中的哨兵模式,其每個(gè)節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)是一樣的,浪費(fèi)內(nèi)存,并且不好在線擴(kuò)容。當(dāng)有海量數(shù)據(jù)需要存儲(chǔ)、高并發(fā)的寫問(wèn)題出現(xiàn)時(shí)候,就要采取分片集群的方式來(lái)解決問(wèn)題了。
4.1 分片集群的特征
集群中有多個(gè)master,每個(gè)master保存不同數(shù)據(jù)
每個(gè)master都可以有多個(gè)slave節(jié)點(diǎn)
master之間通過(guò)ping監(jiān)測(cè)彼此健康狀態(tài)(代替哨兵),如果掛掉了會(huì)故障轉(zhuǎn)移。
客戶端請(qǐng)求可以訪問(wèn)集群任意節(jié)點(diǎn),最終都會(huì)被轉(zhuǎn)發(fā)到正確節(jié)點(diǎn)
?4.2 散列插槽
????????插槽算法把整個(gè)數(shù)據(jù)庫(kù)被分為16384個(gè)slot(槽),每個(gè)進(jìn)入Redis的鍵值對(duì),根據(jù)key進(jìn)行散列,分配到這16384插槽中的一個(gè)。使用的哈希映射也比較簡(jiǎn)單,用CRC16算法計(jì)算出一個(gè)16 位的值,再對(duì)16384取模。數(shù)據(jù)庫(kù)中的每個(gè)鍵都屬于這16384個(gè)槽的其中一個(gè),集群中的每個(gè)節(jié)點(diǎn)都可以處理這16384個(gè)槽。
????????集群中的每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分的hash槽,比如當(dāng)前集群有A、B、C個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)上的哈希槽數(shù) =16384/3,那么就有:
節(jié)點(diǎn)A負(fù)責(zé)0~5460號(hào)哈希槽
節(jié)點(diǎn)B負(fù)責(zé)5461~10922號(hào)哈希槽
節(jié)點(diǎn)C負(fù)責(zé)10923~16383號(hào)哈希槽
即:?數(shù)據(jù)key不是與節(jié)點(diǎn)綁定,而是與插槽綁定。 這樣,三個(gè)節(jié)點(diǎn)分別處理不同的槽位置的數(shù)據(jù),在存、取數(shù)據(jù)時(shí),會(huì)根據(jù)運(yùn)算得到的槽,自動(dòng)切換節(jié)點(diǎn)。
??4.3 動(dòng)態(tài)擴(kuò)容、縮容
? ? ? ? 在4.2節(jié)的基礎(chǔ)上,我們知道,實(shí)際上數(shù)據(jù)不是存儲(chǔ)在節(jié)點(diǎn)上的,而是插槽上的。因此,如果想增加新的節(jié)點(diǎn)時(shí),給新的節(jié)點(diǎn)分配插槽即可。如果想刪掉舊的節(jié)點(diǎn)時(shí),先把插槽轉(zhuǎn)移給別的節(jié)點(diǎn),再把沒有插槽的空節(jié)點(diǎn)刪了即可。
(1)動(dòng)態(tài)擴(kuò)容舉例? ? ?
????????使用redis-cli的add-node命令新增一個(gè)主節(jié)點(diǎn)8007(master),前面的ip:port為新增節(jié)點(diǎn),后面的ip:port為集群中已存在的節(jié)點(diǎn)。????????
src/redis-cli --cluster add-node 192.168.100.100:8007 192.168.100.100:8001
?????????當(dāng)添加節(jié)點(diǎn)成功以后,新增的節(jié)點(diǎn)不會(huì)有任何數(shù)據(jù),因?yàn)樗€沒有分配任何的slot(hash槽),我們需要為新節(jié)點(diǎn)手工分配hash槽。
????????使用redis-cli的rehash命令為8007分配hash槽,找到集群中的任意一個(gè)主節(jié)點(diǎn),對(duì)其進(jìn)行重新分片工作。
src/redis-cli --cluster reshard 192.168.100.100:8001
How many slots do you want to move (from 1 to 16384)? 600
(ps:需要多少個(gè)槽移動(dòng)到新的節(jié)點(diǎn)上,自己設(shè)置,比如600個(gè)hash槽)
What is the receiving node ID? 2728a594a0498e98e4b83a537e19f9a0a3790f38
(ps:把這600個(gè)hash槽移動(dòng)到哪個(gè)節(jié)點(diǎn)上去,需要指定節(jié)點(diǎn)id)
Please enter all the source node IDs.
? Type 'all' to use all the nodes as source nodes for the hash slots.
? Type 'done' once you entered all the source nodes IDs.
Source node 1:all
(ps:輸入all為從所有主節(jié)點(diǎn)(8001,8002,8003)中分別抽取相應(yīng)的槽數(shù)指定到新節(jié)點(diǎn)中,抽取的總槽數(shù)為600個(gè))
?... ...
Do you want to proceed with the proposed reshard plan (yes/no)? yes
(ps:輸入yes確認(rèn)開始執(zhí)行分片任務(wù))
????????槽位遷移后,對(duì)應(yīng)槽位中的數(shù)據(jù)也會(huì)遷移!?
(2)動(dòng)態(tài)縮容舉例? ??
?????????例如,我們將(1)中的8007節(jié)點(diǎn)刪除:
????????因?yàn)橹鞴?jié)點(diǎn)8007的里面是有分配了hash槽的,所以我們這里必須先把8007里的hash槽放入到其他的可用主節(jié)點(diǎn)中去,然后再進(jìn)行移除節(jié)點(diǎn)操作,不然會(huì)出現(xiàn)數(shù)據(jù)丟失問(wèn)題。
src/redis-cli ?--cluster reshard 192.168.100.100:8007
?... ...
How many slots do you want to move (from 1 to 16384)? 600
What is the receiving node ID? baf0c2f3afde2410e34351a8261a703f1394cee9
(ps:這里是需要把數(shù)據(jù)移動(dòng)到哪?8001的主節(jié)點(diǎn)id)
Please enter all the source node IDs.
? Type 'all' to use all the nodes as source nodes for the hash slots.
? Type 'done' once you entered all the source nodes IDs.
Source node 1:4b339ad25b4884c2ff6de8a8ec2bc8766f8faf0b
(ps:這里是需要數(shù)據(jù)源,也就是我們的8007節(jié)點(diǎn)id)
Source node 2:done
(ps:這里直接輸入done 開始生成遷移計(jì)劃)
?... ...
Do you want to proceed with the proposed reshard plan (yes/no)? Yes
(ps:這里輸入yes開始遷移)
????????至此,我們已經(jīng)成功的把8007主節(jié)點(diǎn)的數(shù)據(jù)遷移到8001上去了,我們可以看一下現(xiàn)在的集群狀態(tài)如下圖,你會(huì)發(fā)現(xiàn)8007下面已經(jīng)沒有任何hash槽了,證明遷移成功!?????????
????????最后我們直接使用del-node命令刪除8007主節(jié)點(diǎn)即可文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-480306.html
?src/redis-cli ?--cluster del-node 192.168.100.100:8007 4b339ad25b4884c2ff6de8a8ec2bc8766f8faf0b文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-480306.html
到了這里,關(guān)于Redis集群(分布式緩存):詳解持久化、主從同步原理、哨兵機(jī)制、Cluster分片集群,實(shí)現(xiàn)高并發(fā)高可用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!