redis深度歷險(xiǎn)分為兩個(gè)部分,單機(jī)Redis和分布式Redis。
“專業(yè)、務(wù)實(shí)、高效、創(chuàng)新、把客戶的事當(dāng)成自己的事”是我們每一個(gè)人一直以來堅(jiān)持追求的企業(yè)文化。 創(chuàng)新互聯(lián)是您可以信賴的網(wǎng)站建設(shè)服務(wù)商、專業(yè)的互聯(lián)網(wǎng)服務(wù)提供商! 專注于成都做網(wǎng)站、成都網(wǎng)站建設(shè)、軟件開發(fā)、設(shè)計(jì)服務(wù)業(yè)務(wù)。我們始終堅(jiān)持以客戶需求為導(dǎo)向,結(jié)合用戶體驗(yàn)與視覺傳達(dá),提供有針對性的項(xiàng)目解決方案,提供專業(yè)性的建議,創(chuàng)新互聯(lián)建站將不斷地超越自我,追逐市場,引領(lǐng)市場!
本文為分布式Redis深度歷險(xiǎn)系列的第一篇,主要內(nèi)容為Redis的復(fù)制功能。
Redis的復(fù)制功能的作用和大多數(shù)分布式存儲系統(tǒng)一樣,就是為了支持主從設(shè)計(jì),主從設(shè)計(jì)的好處有以下幾點(diǎn):
讀寫分離,提高讀寫性能
數(shù)據(jù)備份,減少數(shù)據(jù)丟失的風(fēng)險(xiǎn)
高可用,避免單點(diǎn)故障
Redis的復(fù)制主要分為同步和命令傳播兩個(gè)步驟:
同步可以理解為全量,是將主服務(wù)器某一時(shí)刻的所有數(shù)據(jù)全部同步到從服務(wù)器。
命令傳播可以理解為增量,當(dāng)主服務(wù)器數(shù)據(jù)被修改時(shí),主服務(wù)器向從服務(wù)器發(fā)送對應(yīng)的數(shù)據(jù)修改命令。
同步分為以下幾個(gè)步驟:
1.從服務(wù)器向主服務(wù)器發(fā)送SYNC
命令(執(zhí)行SLAVE OF
命令的第一步也會執(zhí)行SYNC
)
2.主服務(wù)器在收到從服務(wù)器命令時(shí),會執(zhí)行BGSAVE
,也就是新開一個(gè)子進(jìn)程將內(nèi)存中的數(shù)據(jù)保存到RDB文件中。同時(shí)使用一個(gè)內(nèi)存緩沖區(qū)記錄從現(xiàn)在開始執(zhí)行的寫命令,該內(nèi)存緩沖區(qū)的作用就是記錄RDB文件生成期間的增量。
3.向從服務(wù)器發(fā)送RDB文件
4.將緩沖區(qū)中的寫命令發(fā)送給從服務(wù)器
同步可以分為兩種情況,一種是從服務(wù)器第一次連接主服務(wù)器,另一種是從服務(wù)與主服務(wù)器的網(wǎng)絡(luò)鏈接斷開了,重新連上主服務(wù)器并重新同步。
命令傳播實(shí)現(xiàn)邏輯比較簡單,當(dāng)主服務(wù)器執(zhí)行了寫命令后,為了保證從服務(wù)器與主服務(wù)器數(shù)據(jù)的一致性,主服務(wù)器會將寫命令發(fā)送給從服務(wù)器,從服務(wù)器執(zhí)行完收到的寫命令后其數(shù)據(jù)就能和主服務(wù)器保持一致了(當(dāng)然會有延時(shí)),注意,從服務(wù)器對于客戶端來說是只讀的,因此從服務(wù)器的所有數(shù)據(jù)都是來自于主服務(wù)器的同步or命令傳播。
假設(shè)Redis主從服務(wù)器之間的網(wǎng)絡(luò)環(huán)境不太可靠,我們來看看上述復(fù)制方法會出現(xiàn)什么問題。假設(shè)有主服務(wù)器A和從服務(wù)器B,主服務(wù)器中目前存在1-10000共一萬條數(shù)據(jù)。
1.初始連接,從服務(wù)器第一次從主服務(wù)器同步數(shù)據(jù),同步完成后,從服務(wù)器也有1-10000共一萬條數(shù)據(jù)。
2.主服務(wù)器新增10001,10002兩條數(shù)據(jù)
3.通過命令傳播,從服務(wù)器也新增10001,10002兩條數(shù)據(jù)
4.這時(shí)候主從服務(wù)器之間的網(wǎng)絡(luò)斷開
5.主服務(wù)器新增數(shù)據(jù)10003,因?yàn)榫W(wǎng)絡(luò)斷開,所以從服務(wù)器感受不到數(shù)據(jù)變化
6.網(wǎng)絡(luò)恢復(fù),從服務(wù)器重新連接上主服務(wù)器,并發(fā)送SYNC命令,進(jìn)行同步操作
7.主服務(wù)器將所有數(shù)據(jù)發(fā)送給從服務(wù)器(1-10003)
從上述步驟中可以看到,當(dāng)從服務(wù)器重新連接上主服務(wù)器時(shí),會重新進(jìn)行全量同步,造成大量不必要的IO開銷,如果網(wǎng)絡(luò)環(huán)境不穩(wěn)定時(shí),會導(dǎo)致主服務(wù)器一直將內(nèi)存中的數(shù)據(jù)寫到磁盤再發(fā)送給從服務(wù)器。
為了解決老版復(fù)制問題,Redis2.8對于復(fù)制功能進(jìn)行了優(yōu)化。實(shí)現(xiàn)如下:
1.主服務(wù)器會維護(hù)一個(gè)偏移量,每次向服務(wù)器傳播N個(gè)字節(jié)的數(shù)據(jù)時(shí),該偏移量就會加上N,比如說一開始是0,接受到一條set key1 value1
后,其偏移量就為13(真實(shí)偏移可能不是13,只是舉個(gè)例子)。//這里可能要看下代碼確認(rèn)
2.從服務(wù)器也維護(hù)一個(gè)偏移量,當(dāng)從服務(wù)器收到到主服務(wù)器的N個(gè)字節(jié)數(shù)據(jù)時(shí),該偏移量會加上N。
3.主服務(wù)器維護(hù)一個(gè)固定大小的緩沖區(qū),每次接受到客戶端寫命令后,都會將對應(yīng)命令
往這個(gè)緩沖區(qū)寫入。當(dāng)寫入內(nèi)容超出固定大小后,會覆蓋原來的數(shù)據(jù)。
4.主服務(wù)器有一個(gè)唯一id
5.從服務(wù)器連接上主服務(wù)時(shí),會向主服務(wù)器發(fā)送上一次連接的主服務(wù)器的id以及偏移量,這里又分幾種情況:
如果從服務(wù)器沒傳id或者id與當(dāng)前主服務(wù)器不匹配,那主服務(wù)器將傳送全量數(shù)據(jù)
如果從服務(wù)器的offset在緩沖區(qū)中不能找到(落后太多導(dǎo)致緩沖區(qū)已經(jīng)被新數(shù)據(jù)覆蓋了),那也會進(jìn)行全量同步
如果offset能在緩沖區(qū)找到,則主服務(wù)從offset開始,將緩沖區(qū)的數(shù)據(jù)依次發(fā)送給從服務(wù)器。(有做pipeline的優(yōu)化嗎)
以上就是新版復(fù)制的大致思路,要注意的是,主服務(wù)器緩沖區(qū)的大小設(shè)置很關(guān)鍵,如果設(shè)置的太大會導(dǎo)致空間浪費(fèi),如果太小會導(dǎo)致網(wǎng)絡(luò)環(huán)境不好時(shí),其退化為老版復(fù)制。
之前我就踩過這樣的坑:在上云時(shí),redis集群在兩個(gè)不同機(jī)房,主從之前網(wǎng)絡(luò)環(huán)境不太穩(wěn)定,而redis機(jī)器上存儲的value比較大,很容易就將緩沖區(qū)占滿導(dǎo)致每次全量同步,形成惡性循環(huán),從服務(wù)器落后不可讀,主服務(wù)器不可寫(當(dāng)從Redis落后太多時(shí),主Redis將拒絕寫入,具體參數(shù)可以配置的,下文還會提到)
所以建議將緩沖區(qū)大小設(shè)置為平均重連間隔*每秒寫入數(shù)據(jù)量*2
從服務(wù)器默認(rèn)會每秒一次的頻率向主服務(wù)器發(fā)送心跳:REPLCONF A?K <replication_offset>
,
replication_offset代表從服務(wù)器當(dāng)前的復(fù)制偏移量。
心跳有三個(gè)作用:
1.檢測主從服務(wù)器的網(wǎng)絡(luò)連接
2.實(shí)現(xiàn)min-slaves功能
3.檢測命令丟失
主服務(wù)器會記錄從服務(wù)器上次發(fā)送心跳是什么時(shí)間,根據(jù)這個(gè)時(shí)間,我們能知道主從服務(wù)器之間的連接是不是出現(xiàn)了故障
Redis為了保證數(shù)據(jù)的安全性,可以配置當(dāng)從服務(wù)器小于min-slaves-to-write
個(gè)或者min-slaves-to-write
個(gè)從服務(wù)器的延遲都大于等于min-slaves-max-lag
時(shí),主服務(wù)器拒絕寫。
主從之間的復(fù)制,其實(shí)是以主服務(wù)器作為從服務(wù)器的客戶端來實(shí)現(xiàn)的(在Redis中,所有服務(wù)器之間的數(shù)據(jù)傳遞都是以該種方式)。假設(shè)主服務(wù)器向從服務(wù)器發(fā)送一條寫命令,但網(wǎng)絡(luò)出現(xiàn)異常,從服務(wù)器并沒有收到該命令。
這就會導(dǎo)致數(shù)據(jù)不一致的狀態(tài)(你可能想主服務(wù)器發(fā)送命令時(shí),如果從沒返回失敗,進(jìn)行重發(fā)不就好了嗎?如果說從成功執(zhí)行了命令,但是再回復(fù)主的時(shí)候出現(xiàn)了問題,那主如果重發(fā)就會造成數(shù)據(jù)異常了)。所以主服務(wù)器會根據(jù)心跳信息來決定要發(fā)送的數(shù)據(jù)??磦€(gè)例子:
初始,主服務(wù)器和從服務(wù)器偏移量都是100。
主服務(wù)器收到客戶端的寫命令,將偏移量改成110,同時(shí)向從服務(wù)器發(fā)送寫命令,但因網(wǎng)絡(luò)原因,從服務(wù)器并沒有收到,其偏移量仍然是100。主服務(wù)器根據(jù)心跳發(fā)現(xiàn)從服務(wù)器的偏移量是100落后于自己,所以會將100-110的數(shù)據(jù)進(jìn)行重發(fā)。
?
看到這里,你可能對于上述方案的正確性感到質(zhì)疑:在從服務(wù)器接收到100-110的數(shù)據(jù)前,它發(fā)送心跳包告訴主服務(wù)器自己當(dāng)前偏移為100,然后接收到了100-110的數(shù)據(jù)。這時(shí)下個(gè)心跳還沒發(fā)出,主服務(wù)器認(rèn)為從服務(wù)器落后于自己,再次發(fā)送100-110的數(shù)據(jù),導(dǎo)致從服務(wù)器再次寫入100-110的數(shù)據(jù),導(dǎo)致數(shù)據(jù)異常!
?
如果你有想到這個(gè)問題,說明你是有在認(rèn)真思考了~
其實(shí)是不存在這種情況的,原因是redis是單線程的!記住單線程三個(gè)字,再回頭看一遍問題描述,相信你能想明白~
?
網(wǎng)站欄目:分布式Redis深度歷險(xiǎn)-復(fù)制
URL分享:http://jinyejixie.com/article22/gcepjc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、定制網(wǎng)站、Google、建站公司、網(wǎng)站維護(hù)、搜索引擎優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)