早期的RDBMS被設計爲運行在單個CPU之上,讀寫操做都由經單個數據庫實例完成,複製技術使得數據庫的讀寫操做能夠分散在運行於不一樣CPU之上的獨立服務器上,Redis做爲一個開源的、優秀的key-value緩存及持久化存儲解決方案,也提供了複製功能,本文主要介紹Redis的複製原理及特性。redis
數據庫複製指的是發生在不一樣數據庫實例之間,單向的信息傳播的行爲,一般由被複制方和複製方組成,被複制方和複製方之間創建網絡鏈接,複製方式一般爲被複制方主動將數據發送到複製方,複製方接收到數據存儲在當前實例,最終目的是爲了保證雙方的數據一致、同步。數據庫
複製示意圖編程
Redis的複製方式有兩種,一種是主(master)-從(slave)模式,一種是從(slave)-從(slave)模式,所以Redis的複製拓撲圖會豐富一些,能夠像星型拓撲,也能夠像個有向無環:緩存
Redis集羣複製結構圖安全
經過配置多個Redis實例獨立運行、定向複製,造成Redis集羣,master負責寫、slave負責讀。服務器
經過配置多個Redis實例,數據備份在不一樣的實例上,主庫專一寫請求,從庫負責讀請求,這樣的好處主要體如今下面幾個方面:網絡
在一個Redis集羣中,若是master宕機,slave能夠介入並取代master的位置,所以對於整個Redis服務來講不至於提供不了服務,這樣使得整個Redis服務足夠安全。less
在一個Redis集羣中,master負責寫請求,slave負責讀請求,這麼作一方面經過將讀請求分散到其餘機器從而大大減小了master服務器的壓力,另外一方面slave專一於提供讀服務從而提升了響應和讀取速度。異步
經過增長slave機器能夠橫向(水平)擴展Redis服務的整個查詢服務的能力。分佈式
複製提供了高可用性的解決方案,但同時引入了分佈式計算的複雜度問題,認爲有兩個核心問題:
上面兩個問題,尤爲是第一個問題是Redis服務實現一直在演變,致力於解決的一個問題。
Redis提供了提升數據一致性的解決方案,本文後面會進行介紹,一致性程度的增長雖然使得我可以更信任數據,可是更好的一致性方案一般伴隨着性能的損失,從而減小了吞吐量和服務能力。然而咱們但願系統的性能達到最優,則必需要犧牲一致性的程度,所以Redis的複製實時性和數據一致性是存在矛盾的。
舉個例子,咱們有四臺redis實例,M1,R一、R二、R3,其中M1爲master,R一、R二、R3分別爲三臺slave redis實例。在M1啓動以下:
./redis-server ../redis8000.conf --port 8000
下面分別爲R一、R二、R3的啓動命令:
./redis-server ../redis8001.conf --port 8001 --slaveof 127.0.0.1 8000 ./redis-server ../redis8002.conf --port 8002 --slaveof 127.0.0.1 8000 ./redis-server ../redis8003.conf --port 8003 --slaveof 127.0.0.1 8000
這樣,咱們就成功的啓動了四臺Redis實例,master實例的服務端口爲8000,R一、R二、R3的服務端口分別爲800一、800二、8003,集羣圖以下:
Redis集羣複製拓撲
上面的命令在slave啓動的時候就指定了master機器,咱們也能夠在slave運行的時候經過slaveof命令來指定master機器。
Redis複製主要由SYNC命令實現,複製過程以下圖:
Redis複製過程
上圖爲Redis複製工做過程:
值得注意的是,當slave跟master的鏈接斷開時,slave能夠自動的從新鏈接master,在redis2.8版本以前,每當slave進程掛掉從新鏈接master的時候都會開始新的一輪全量複製。若是master同時接收到多個slave的同步請求,則master只須要備份一次RDB文件。
上面複製過程介紹的最後提到,slave和master斷開了、當slave和master從新鏈接上以後須要全量複製,這個策略是很不友好的,從Redis2.8開始,Redis提供了增量複製的機制:
增量複製機制
master除了備份RDB文件以外還會維護者一個環形隊列,以及環形隊列的寫索引和slave同步的全局offset,環形隊列用於存儲最新的操做數據,當slave和maste斷開重連以後,會把slave維護的offset,也就是上一次同步到哪裏的這個值告訴master,同時會告訴master上次和當前slave鏈接的master的runid,知足下面兩個條件,Redis不會全量複製:
知足上面兩個條件,Redis就不會全量複製,這樣的好處是大大的提升的性能,不作無效的功。
增量複製是由psync命令實現的,slave能夠經過psync命令來讓Redis進行增量複製,固然最終是否可以增量複製取決於環形隊列的大小和slave的斷線時間長短和重連的這個master是不是以前的master。
環形隊列大小配置參數:
repl-backlog-size 1mb
Redis同時也提供了當沒有slave須要同步的時候,多久能夠釋放環形隊列:
repl-backlog-ttl 3600
免持久化機制官方叫作Diskless Replication,前面基於RDB文件寫磁盤的方式能夠看出,Redis必需要先將RDB文件寫入磁盤,才進行網絡傳輸,那麼爲何不能直接經過網絡把RDB文件傳送給slave呢?免持久化複製就是作這個事情的,並且在Redis2.8.18版本開始支持,固然目前仍是實驗階段。
值得注意的是,一旦基於Diskless Replication的複製傳送開始,新的slave請求須要等待此次傳輸完畢纔可以獲得服務。
是否開啓Diskless Replication的開關配置爲:
repo-diskless-sync no
爲了讓後續的slave可以儘可能遇上本次複製,Redis提供了一個參數配置指定複製開始的時間延遲:
repl-diskless-sync-delay 5
自從Redis2.6版本開始,支持對slave的只讀模式的配置,默認對slave的配置也是隻讀。只讀模式的slave將會拒絕客戶端的寫請求,從而避免由於從slave寫入而致使的數據不一致問題。
和MySQL複製策略有點相似,Redis複製自己是異步的,但也提供了半同步的複製策略,半同步複製策略在Redis複製中的語義是這樣的:
容許用戶給出這樣的配置:在maste接受寫操做的時候,只有當必定時間間隔內,至少有N臺slave在線,不然寫入無效。
上面功能的實現基於Redis下面特性:
咱們能夠經過下面配置來指定時間間隔和N這個值:
min-slaves-to-write <number of slaves> min-slaves-max-lag <number of seconds>
當配置了上面兩個參數以後,一旦對於一個寫操做沒有知足上面的兩個條件,則master會報錯,而且將本次寫操做視爲無效。這有點像CAP理論中的「C」,即一致性實現,雖然半同步策略不可以徹底保證master和slave的數據一致性,可是相對減小了不一致性的窗口期。
本文在理解Redis複製概念和複製的優缺點的基礎之上介紹了當前Redis複製工做原理以及主要特性,但願可以幫助你們。