概述
一般來說客年,要將Redis運(yùn)用于工程項(xiàng)目中量瓜,只使用一臺Redis是萬萬不能的,原因如下:
- 從結(jié)構(gòu)上绍傲,單個Redis服務(wù)器會發(fā)生單點(diǎn)故障唧取,并且一臺服務(wù)器需要處理所有的請求負(fù)載枫弟,壓力較大;
- 從容量上骇塘,單個Redis服務(wù)器內(nèi)存容量有限款违,就算一臺Redis服務(wù)器內(nèi)容容量為256G插爹,也不能將所有內(nèi)容用作Redis存儲內(nèi)存请梢,一般來說毅弧,單臺Redis最大使用內(nèi)存不應(yīng)該超過20G够坐。
本文先討論第一點(diǎn)的解決方案:Redis主從復(fù)制元咙,第二點(diǎn)可以使用Redis集群解決,下一篇文章將介紹Redis集群光酣。
主從復(fù)制
考慮如下一種場景:
電子商務(wù)網(wǎng)站上的商品脉课,一般都是一次上傳倘零,無數(shù)次瀏覽的呈驶,說專業(yè)點(diǎn)也就是"多讀少寫"疫鹊。
對于這種場景司致,我們可以使如下這種架構(gòu):
![Redis主從復(fù)制結(jié)構(gòu)圖](http://7xlune.com1.z0.glb.clouddn.com/images/Redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E6%9E%B6%E6%9E%84.png)
如圖中所示,我們將一臺Redis服務(wù)器作主庫(Matser)霉晕,其他三臺作為從庫(Slave)牺堰,主庫只負(fù)責(zé)寫數(shù)據(jù)伟葫,每次有數(shù)據(jù)更新都將更新的數(shù)據(jù)同步到它所有的從庫,而從庫只負(fù)責(zé)讀數(shù)據(jù)奶卓。這樣一來夺姑,就有了兩個好處:
- 讀寫分離盏浙,不僅可以提高服務(wù)器的負(fù)載能力废膘,并且可以根據(jù)讀請求的規(guī)模自由增加或者減少從庫的數(shù)量丐黄,棒極了灌闺;
- 數(shù)據(jù)被復(fù)制成了了好幾份桂对,就算有一臺機(jī)器出現(xiàn)故障蕉斜,也可以使用其他機(jī)器的數(shù)據(jù)快速恢復(fù)宅此。
需要注意的是:在Redis主從模式中父腕,一臺主庫可以擁有多個從庫,但是一個從庫只能隸屬于一個主庫痢法。
配置
在Redis中财搁,要實(shí)現(xiàn)主從復(fù)制架構(gòu)非常簡單躬络,只需要在從數(shù)據(jù)庫的配置文件中加上如下命令即可:
slaveof 主數(shù)據(jù)庫地址 主數(shù)據(jù)庫端口
主數(shù)據(jù)庫不需要任何配置提茁。
示例
下面將演示怎么實(shí)現(xiàn)一個簡單的復(fù)制系統(tǒng)馁菜。我們在一臺機(jī)器上起兩個Redis實(shí)例汪疮,監(jiān)聽不同的端口智嚷,其中一個作為主庫稍浆,另外一個作為從庫猜嘱。首先不加任何參數(shù)來啟動一個Redis實(shí)例作為主數(shù)據(jù)庫:
![](http://7xlune.com1.z0.glb.clouddn.com/images/Redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/%E5%90%AF%E5%8A%A8%E4%B8%BB%E5%BA%93.png)
可以看到泉坐,主庫監(jiān)聽的是6379端口腕让。
然后加上slaveof參數(shù)啟動另一個Redis實(shí)例作為從庫纯丸,并且監(jiān)聽6380端口:
![](http://7xlune.com1.z0.glb.clouddn.com/images/Redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/%E5%90%AF%E5%8A%A8%E4%BB%8E%E5%BA%93.png)
從控制臺輸出中可以看到偏形,從庫已經(jīng)連接到主庫:126.0.0.1:6379了,看樣子主從復(fù)制系統(tǒng)配置成功觉鼻。我們可以分別在主庫和從庫中使用如下命令看一看當(dāng)前實(shí)例在復(fù)制系統(tǒng)中的相關(guān)信息:
![](http://7xlune.com1.z0.glb.clouddn.com/images/Redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/Redis%E8%A7%92%E8%89%B2.png)
接下來驗(yàn)證一把俊扭。
首先在主庫中設(shè)置一個鍵值:
[qifuguang@Mac~]$ /opt/soft/redis-3.0.4/src/redis-cli -p 6379
127.0.0.1:6379> set test-sync winwill2012
OK
127.0.0.1:6379>
現(xiàn)在到從庫中檢查該值是否已經(jīng)自動同步到了從庫:
[qifuguang@Mac~]$ /opt/soft/redis-3.0.4/src/redis-cli -p 6380
127.0.0.1:6380> get test-sync
"winwill2012"
127.0.0.1:6380>
可以看到,數(shù)據(jù)確實(shí)從主庫同步到了從庫.
在默認(rèn)情況下坠陈,從庫是只讀的萨惑,如果在從庫中寫數(shù)據(jù)將會報錯:
[qifuguang@Mac~]$ /opt/soft/redis-3.0.4/src/redis-cli -p 6380
127.0.0.1:6380> set x y
(error) READONLY You can't write against a read only slave.
127.0.0.1:6380>
但是可以在從庫的配置文件中加上如下的配置項(xiàng)允許從庫寫數(shù)據(jù):
slave-read-only no
但是,因?yàn)閺膸熘行薷牡臄?shù)據(jù)不會被同步到任何其他數(shù)據(jù)庫仇矾,并且一旦主庫修改了數(shù)據(jù)庸蔼,從庫的數(shù)據(jù)就會因?yàn)樽詣油奖桓采w,所以一般情況下贮匕,不建議將從庫設(shè)置為可寫掏膏。
相同的道理,配置多臺從庫也使用相同的方法,都在從庫的配置文件中加上slaveof參數(shù)即可。
此外,我們可以在客戶端使用命令
SLAVEOF 新主庫地址 新主庫端口
來修改當(dāng)前數(shù)據(jù)庫的主庫,如果當(dāng)前數(shù)據(jù)庫已經(jīng)是其他庫的從庫葫男, 則當(dāng)前數(shù)據(jù)庫會停止和原來的數(shù)據(jù)庫的同步而和新的數(shù)據(jù)庫同步盈咳。
最后丈积,從數(shù)據(jù)庫還可以通過運(yùn)行命令:
SLAVEOF NO ONE
來停止接受來自其他數(shù)據(jù)庫的同步而升級成為主庫。
原理
上面說了配置主從復(fù)制系統(tǒng)的方法,并且舉例例子詳細(xì)說明,本節(jié)將介紹Redis主從復(fù)制的實(shí)現(xiàn)原理。
當(dāng)一個從數(shù)據(jù)庫啟動時,會向主數(shù)據(jù)庫發(fā)送SYNC命令,主數(shù)據(jù)庫收到命令后會開始在后臺保存快照(即RDB持久化過程),并將保存快照期間接收到的命令緩存起來。當(dāng)快照完成后,Redis會將快照文件和緩存的命令發(fā)給從數(shù)據(jù)庫痛垛,從數(shù)據(jù)庫收到數(shù)據(jù)后冠蒋,會載入快照文件并執(zhí)行緩存的命令斩郎。以上過程稱為復(fù)制初始化锻煌。復(fù)制初始化之結(jié)束后捂龄,主數(shù)據(jù)庫每收到寫命令時就會將命令同步給從數(shù)據(jù)庫局荚,從而保證主從數(shù)據(jù)庫數(shù)據(jù)一致首装,這一過程稱為復(fù)制同步階段系奉。
有兩點(diǎn)需要注意:
- 當(dāng)主從數(shù)據(jù)庫之間的連接斷開后,Redis2.8之前的版本會重新進(jìn)行復(fù)制初始化過程鸳粉,這樣就使得主從數(shù)據(jù)庫斷開連接后數(shù)據(jù)恢復(fù)的過程的效率很低下艰山。Redis2.8版本的一個重要改進(jìn)就是斷線支持有條件的增量數(shù)據(jù)傳輸织鲸,當(dāng)從數(shù)據(jù)庫再次連接到主數(shù)據(jù)庫時,主數(shù)據(jù)庫只需要將斷線期間執(zhí)行的命令發(fā)給從數(shù)據(jù)庫即可茬暇,大大提高了Redis主從復(fù)制的實(shí)用性。
- 復(fù)制同步階段貫穿整個主從同步過程的始終赊颠,直到主從關(guān)系終止為止。在復(fù)制過程中,即使關(guān)閉了RDB方式的持久化(刪除所有save參數(shù))抄淑,依舊會執(zhí)行快照操作。
樂觀復(fù)制
Redis采用了復(fù)制的策略酸役。容忍在一定時間內(nèi)主從數(shù)據(jù)庫的內(nèi)容是不同的事格,但是兩者的數(shù)據(jù)最終會保持一致绷柒。具體來說,Redis主從數(shù)據(jù)庫之間的復(fù)制數(shù)據(jù)的過程本身是異步的涮因,這意味著废睦,主數(shù)據(jù)庫執(zhí)行完客戶端的寫請求后會立即將命令在主數(shù)據(jù)庫的執(zhí)行結(jié)果返回給客戶端,而不會等待從數(shù)據(jù)庫收到該命令后再返回給客戶端养泡。這一特性保證了復(fù)制后主從數(shù)據(jù)庫的性能不會受到影響嗜湃,但另一方面也會產(chǎn)生一個主從數(shù)據(jù)庫數(shù)據(jù)不一致的時間窗口,當(dāng)主數(shù)據(jù)庫執(zhí)行一條寫命令之后澜掩,主數(shù)據(jù)庫的數(shù)據(jù)已經(jīng)發(fā)生變動购披,然而在主數(shù)據(jù)庫將該命令傳送給從數(shù)據(jù)庫之前,如果兩個數(shù)據(jù)庫之間的連接斷開了肩榕,此時二者間的數(shù)據(jù)就不一致了刚陡。從這個角度看,主數(shù)據(jù)庫無法得知命令最終同步給了幾個從數(shù)據(jù)庫株汉,不過Redis提供了兩個配置選項(xiàng)來限制只有至少同步給指定數(shù)量的數(shù)據(jù)庫時筐乳,主數(shù)據(jù)庫才是可寫的:
min-slaves-to-write 3
min-slave2-max-lag 10
第一個參數(shù)表示只有當(dāng)3個或3個以上的從數(shù)據(jù)庫連接到主庫時,主數(shù)據(jù)庫才是可寫的郎逃,否則返回錯誤哥童。
第二個參數(shù)表示允許從數(shù)據(jù)庫失去連接的最長時間,該選項(xiàng)默認(rèn)是關(guān)閉的褒翰,在分布式系統(tǒng)中贮懈,打開并合理配置該選項(xiàng)可以降低主從架構(gòu)因?yàn)榫W(wǎng)絡(luò)分區(qū)導(dǎo)致的數(shù)據(jù)不一致問題。
圖結(jié)構(gòu)
從數(shù)據(jù)庫不僅可以接收主數(shù)據(jù)庫的數(shù)據(jù)优训,同時也可以作為主數(shù)據(jù)庫存在朵你,形成類似圖的結(jié)構(gòu),如下圖:
![](http://7xlune.com1.z0.glb.clouddn.com/images/Redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/%E5%9B%BE%E7%BB%93%E6%9E%84.png)
A中的數(shù)據(jù)會同步到B,C中揣非,C中的數(shù)據(jù)會同步到D,E中抡医。
聲明
本文首發(fā)于個人技術(shù)博客,轉(zhuǎn)載請注明出處 ,本文鏈接:
http://qifuguang.me/2015/10/18/Redis主從復(fù)制
如果你喜歡我的文章忌傻,請關(guān)注我的微信訂閱號:“機(jī)智的程序猿”大脉,更多精彩,盡在其中:
![](http://7xlune.com1.z0.glb.clouddn.com/%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.jpg)