在分布式系統中,希望使用多個服務器來部署redis,存在以下幾種redis的部署方式
- 主從模式
- 主從+哨兵
- 集群模式
主從模式
在若干個redis節點中,有的是主節點,有的是從節點
假設有三個物理服務器(稱為是三個節點)
分別部署了一個redis-server進程,此時就可以把其中的一個節點作為主節點,另外兩個作為從節點,從節點的數據跟隨主節點變化,從節點的數據要和主節點保持一致,如果改了從節點的數據,不可以把從節點的數據同步到主節點中
如果從節點掛了,沒有什么影響,但如果是主節點掛了,有一定影響,因為從節點只能讀取數據,如果要寫數據就沒有節點可以寫了,如果我們設置多個主節點的話,數據同步會比較麻煩
操作
正常來說,每個redis服務器程序,應該是在一個單獨的主機上,由于我沒有多個服務器,我就在一個服務器運行多個redis-server進程,此時需要保證多個redis-server端口是不同的
redis啟動時指定啟動端口的方法:
- 啟動的時候,通過命令行來指定端口,- -port選項
- 直接在配置文件中,設定端口
我們把/etc/redis/redis.conf拷貝到一個目錄下,然后對這兩個配置文件進行修改
把slave1.conf中的port改為6380,daemonize改為yes(后臺運行),slave2.conf中的port改為6381,daemonize改為yes
啟動redis
使用redis-cli -p 6380,redis-cli -p 6381還有redis-cli啟動三個redis,這個時候在主節點(6379)端口set key 111,6380端口的redis并不能看到,所以這個時候還沒有達成主從復制
建立復制
想要達成主從復制有三種方式:
- 在配置?件中加? slaveof {masterHost} {masterPort} 隨 Redis 啟動?效。→永久生效
- 在 redis-server 啟動命令時加? --slaveof {masterHost} {masterPort} ?效。
- 直接使? redis 命令(在客戶端中):slaveof {masterHost} {masterPort} ?效。→重啟后就按照配置文件中的方案走
這里我們采用第一種方案:vim salve1.conf和vim salve2.conf,在最后面添加,這里以6379為主節點
這時候重新啟動三個redis服務器才可以完成主從復制,通過 redis-cli 可以連接主 Redis 實例,通過 redis-cli -p 6380 連接從 Redis。并且觀察復制關系。
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> get hello
"world"
127.0.0.1:6380> get hello
"world"
從運?結果中看到復制已經?作了,針對主節點 6379 的任何修改都可以同步到從節點 6380 中,復制過程如圖所示。
使用netstat -anp | grep redis-server查看redis進程
又上圖可知,其實主從復制就是主節點和從節點創建TCP連接
1)主節點6379復制狀態信息,用info replication查看
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=100,lag=0
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:100
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:100
2)從節點 6380 復制狀態信息
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:170
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:170
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:170
這里介紹幾個選項的含義:
- offset:相當于是從節點和主節點之間,同步數據的進度,因為主節點上會收到源源不斷的"修改數據”請求,從節點就需要從主節點這里同步這些修改請求,從節點和主節點之問的數據同步,不是瞬問完成的!!
- lag:延遲
- master_replid:主節點的身份標識
- master_replid2:如果master節點宕機了,slave節點成功切換為master后,會將之前master_replid記錄的值存儲到master_replid2中,自己生成一個新的隨機字符,作為自己的master標識,存儲在master_replid中
- master_repl_offset:主節點數據修改了多少
- repl_backlog_active/repl_backlog_size/repl_backlog_first_byte_offset/repl_backlog_histlen:積壓緩沖區,支持部分同步機制的實現
- slave_priority:主節點掛了,選擇從節點作為主節點的優先級
- slave_read_only:從節點是否只讀
- connected_slaves:從節點下面也可以再有從節點,也可以用從節點去同步從節點
關于master_replid和master_replid2可以看這篇文章:replication中的兩個master_replid
斷開復制
slaveof 命令不但可以建?復制,還可以在從節點執? slaveof no one(在客戶端中輸入)來斷開與主節點復制關系。
例如在 6380 節點上執? slaveof no one 來斷開復制。
斷開復制主要流程:
1)斷開與主節點復制關系。
2)從節點晉升為主節點。
從節點斷開復制后并不會拋棄原有數據,只是?法再獲取主節點上的數據變化。
通過 slaveof 命令還可以實現切主操作,將當前從節點的數據源切換到另?個主節點。執?
slaveof {newMasterIp} {newMasterPort} 命令即可。
切主操作主要流程:
1)斷開與舊主節點復制關系。
2)與新主節點建?復制關系。
3)刪除從節點當前所有數據。
4)從新主節點進?復制操作。
安全性
對于數據?較重要的節點,主節點會通過設置 requirepass 參數進?密碼驗證,這時所有的客戶
端訪問必須使? auth 命令實?校驗。從節點與主節點的復制連接是通過?個特殊標識的客戶端來完
成,因此需要配置從節點的masterauth 參數與主節點密碼保持?致,這樣從節點才可以正確地連接到主節點并發起復制流程。
只讀
默認情況下,從節點使? slave-read-only=yes 配置為只讀模式。**由于復制只能從主節點到從節
點,對于從節點的任何修改主節點都?法感知,修改從節點會造成主從數據不?致。**所以建議線上不
要修改從節點的只讀模式。
傳輸延遲
主節點和從節點之間通過網絡來傳輸(TCP),TCP內部支持了nagle算法(默認開啟)
開啟:會增加tcp的傳輸延遲,節省了網絡帶寬
關閉:會減少網絡延遲,增加了網絡帶寬
這個nagle算法和捎帶應答目的是一樣的,針對較小的數據包進行合并,減少了包的個數
redis中repl-disable-tcp-nodelay選項用于在主從同步通信過程中,關閉tcp 的nagle 算法,從節點更快速的和主節點進行同步
拓撲結構
一主一從結構
?主?從結構是最簡單的復制拓撲結構,?于主節點出現宕機時從節點提供故障轉移?持,如圖
所示。當應?寫命令并發量較?且需要持久化時,可以只在從節點上開啟 AOF,這樣既可以保證數據安全性同時也避免了持久化對主節點的性能?擾。但需要注意的是,當主節點關閉持久化功能時,如果主節點宕機要避免?動重啟操作。(如果自動重啟,此時沒有AOF文件,就會丟失數據,進一步的主從同步,會把從節點的數據也刪除掉)
一主多從
?主多從結構(星形結構)使得應?端可以利?多個從節點實現讀寫分離。對于讀?重較?的場景,可以把讀命令負載均衡到不同的從節點上來分擔壓?。同時?些耗時的讀命令可以指定?臺專?的從節點執?,避免破壞整體的穩定性。對于寫并發量較?的場景,多個從節點會導致主節點寫命令的多次發送從?加重主節點的負載。(主節點上數據的修改,就會把改變的數據同步到從節點)
樹形主從結構
樹形主從結構(分層結構)使得從節點不但可以復制主節點數據,同時可以作為其他從節點的主
節點繼續向下層復制。通過引?復制中間層,可以有效降低住系欸按負載和需要傳送給從節點的數據
量數據寫?節點 A 之后會同步給 B 和 C 節點,B 節點進?步把數據同步給 D 和 E 節點。當主節點需要掛載等多個從節點時為了避免對主節點的性能?擾,可以采?這種拓撲結構。
原理
如圖所示,下?詳細介紹建?復制的完整流程。從圖中可以看出復制過程?致分為 6 個過程:
主從節點建?復制流程圖
1)保存主節點(master)的信息。
開始配置主從同步關系之后,從節點只保存主節點的地址信息,此時建?復制流程還沒有開始,
在從節點 6380 執? info replication 可以看到如下信息:
master_host: 127.0.0.1
master_port: 6379
master_link_status: down
從統計信息可以看出,主節點的 ip 和 port 被保存下來,但是主節點的連接狀態(master_link_status)是下線狀態。
2)從節點(slave)內部通過每秒運?的定時任務維護復制相關邏輯,當定時任務發現存在新的主節
點后,會嘗試與主節點建?基于 TCP 的?絡連接。如果從節點?法建?連接,定時任務會?限重試直到連接成功或者?戶停?主從復制。(TCP三次握手驗證通信雙方是否能正確讀取數據,系統層面)
3)發送 ping 命令。連接建?成功之后,從節點通過 ping 命令確認主節點在應?層上是?作良好的。如果 ping 命令的結果 pong 回復超時,從節點會斷開 TCP 連接,等待定時任務下次重新建?連接。
4)權限驗證。如果主節點設置了 requirepass 參數,則需要密碼驗證,從節點通過配置 masterauth
參數來設置密碼。如果驗證失敗,則從節點的復制將會停?。
5)同步數據集。對于?次建?復制的場景,主節點會把當前持有的所有數據全部發送給從節點,這步操作基本是耗時最?的,所以?劃分稱兩種情況:全量同步和部分同步,下?節重點介紹。
6)命令持續復制。當從節點復制了主節點的所有數據之后,針對之后的修改命令,主節點會持續的把命令發送給從節點,從節點執?修改命令,保證主從數據的?致性。
數據同步
Redis 使? psync 命令完成主從數據同步,同步過程分為:全量復制和部分復制。
- 全量復制:?般?于初次復制場景,Redis 早期?持的復制功能只有全量復制,它會把主節點全部數據?次性發送給從節點,當數據量較?時,會對主從節點和?絡造成很?的開銷。
- 部分復制:?于處理在主從復制中因?絡閃斷等原因造成的數據丟失場景,當從節點再次連上主節點后,如果條件允許,主節點會補發數據給從節點。因為補發的數據遠?于全量數據,可以有效避免全量復制的過?開銷。
- 實時復制:從節點,已經和主節點,同步好了數據了(從節點這一時刻已經和主節點數據一致了)但是之后,主節點這邊會源源不斷的收到新的修改數據的請求,主節點上的數據就會隨之改變,也需要能夠同步給從節點
從節點使? psync 命令完成部分復制和全量復制功能,命令格式:psync {replicationId} {offset},參數含義:replicationId 是從節點所復制的主節點的運? ID、offset 是當前從節點已復制的數據偏移量。
全量復制
1)從節點發送 psync 命令給主節點,replicationId 和 offset 的默認值分別是 ? 和 -1。
2)主節點根據 psync 參數和??數據情況決定響應結果:
- 如果回復 +FULLRESYNC replicationId offset,則從節點需要進?全量復制流程。
- 如果回復 +CONTINEU,從節點進?部分復制流程。
- 如果回復 -ERR,說明 Redis 主節點版本過低,不?持 psync 命令。從節點可以使? sync 命令進?全量復制。
psync 并不需要咱們?動執?,Redis 會在主從復制模式下?動調?執?。
1)從節點發送 psync 命令給主節點進?數據同步,由于是第?次進?復制,從節點沒有主節點的運? ID 和復制偏移量,所以發送 psync ? -1。
2)主節點根據命令,解析出要進?全量復制,回復 +FULLRESYNC 響應。
3)從節點接收主節點的運?信息進?保存。
4)主節點執? bgsave 進? RDB ?件的持久化。
5)主節點發送 RDB ?件給從節點,從節點保存 RDB 數據到本地。
6)主節點將從?成 RDB 到接收完成期間執?的寫命令,寫?緩沖區中,等從節點加載完 RDB ?件后,主節點再將緩沖區內的數據補發給從節點,保持主從?致性。
7)從節點清空??原有舊數據。
8)從節點加載 RDB ?件得到與主節點?致的數據。
9)如果從節點加載 RDB 完成之后,并且開啟了 AOF 持久化功能,它會進? bgrewrite 操作,得到最近的 AOF ?件。
由于當前收到的是大批量的數據,此時產生的 aof 日志,整體來說,可能會存在一定的冗余信息,因此針對 aof 日志進行整理,也是必要的過程
Redis Bgrewriteaof 命令用于異步執行一個 AOF(AppendOnly File) 文件重寫操作。重寫會創建一個當前 AOF 文件的體積優化版本。
即使 Bgrewriteaof 執行失敗,也不會有任何數據丟失,因為舊的 AOF 文件在 Bgrewriteaof 成功之前不會被修改。
無硬盤模式:主節點生成的rdb二進制數據,不直接保存到文件中了,而是直接進行網絡傳輸(節省了一系列的讀硬盤和寫硬盤的操作),從節點,直接把收到的數據進行加載
部分復制
部分復制主要是 Redis 針對全量復制的過?開銷做出的?種優化措施,使? psync replicationId offset 命令實現。當從節點正在復制主節點時,如果出現?絡閃斷或者命令丟失等異常情況時,從節點會向主節點要求補發丟失的命令數據,如果主節點的復制積壓緩沖區存在數據則直接發送給從節點,這樣就可以保持主從節點復制的?致性。補發的這部分數據?般遠遠?于全量數據,所以開銷很?。整體流程如圖所示。
1)當主從節點之間出現?絡中斷時,如果超過 repl-timeout 時間,主節點會認為從節點故障并終端 復制連接。
2)主從連接中斷期間主節點依然響應命令,但這些復制命令都因?絡中斷?法及時發送給從節點,所以暫時將這些命令滯留在復制積壓緩沖區中。
3)當主從節點?絡恢復后,從節點再次連上主節點。
4)從節點將之前保存的replicationId 和 復制偏移量作為 psync 的參數發送給主節點,請求進?部分復制。
5)主節點接到 psync 請求后,進?必要的驗證。隨后根據 offset 去復制積壓緩沖區查找合適的數據,并響應 +CONTINUE 給從節點。
6)主節點將需要從節點同步的數據發送給從節點,最終完成?致性。
積壓緩沖區:
就是一個內存中的簡單的隊列,會記錄最近一段時間修改的數據,總量有限,隨著時間的推移,就會把之前的,舊的數據逐漸刪掉。
replicationid 其實就是在描述"數據的來源",offset 描述"數據的復制的進度"
如果 replicationld 不一樣,需要全量復制一下。
如果 replicationld 一樣,offset 再判定。
offset 表示 從節點之前同步數據的進度是如何,主節點就看這個進度是否在當前的積壓緩沖區之內
如果確實是在積壓緩沖區之內,此時就可以直接進行部分復制,就只把最近這段時間的數據給復制過去即可,如果當前從節點的進度已經超出積壓緩沖區的范圍了,需要全量復制。
實時復制
從節點和主節點之間會建立 TCP 的長連接,然后主節點把自己收到的修改數據的請求,通過上述 連接,發給從節點從節點再根據這些修改請求,修改內存中的數據,這個過程也需要時間,正常來說延遲比較小,主從節點在建?復制連接后,它們之間需要維護?連接并彼此發送?跳命令。
1)主從節點彼此都有?跳檢測機制,各?模擬成對?的客戶端進?通信。
2)主節點默認每隔 10 秒對從節點發送 ping命令,判斷從節點的存活性和連接狀態。
3)從節點默認每隔 1 秒向主節點發送 replconf ack {offset} 命令,給主節點上報??當前的復制偏移量。
如果主節點發現從節點通信延遲超過 repl-timeout 配置的值(默認 60 秒),則判定從節點下線,斷開復制客戶端連接。從節點恢復連接后,?跳機制繼續進?
replication id/runid
多數資料對這兩個的區分有所問題,一個redis服務器上,replication id和run id都是存在的
主節點:info replication
info server
從節點:info replication
info server
官方文檔中psync replicationid offset而不是runid
runid主要是用在支持實現redis哨兵的功能的
主從復制總結
主從復制的特點:
- Redis 通過復制功能實現主節點的多個副本。
- 主節點?來寫, 從節點?來讀. 這樣做可以降低主節點的訪問壓?.
- 復制?持多種拓撲結構,可以在適當的場景選擇合適的拓撲結構。
- 復制分為全量復制和部分復制。
- 主從節點之間通過?跳機制保證主從節點通信正常和數據?致性。
主從復制的缺點:
- 從機多了, 復制數據的延時?常明顯.
- 主機掛了, 從機不會升級成主機. 只能通過???預的?式恢復.
redis主節點無法重啟
從節點和主節點斷開連接有兩種情況:
- 從節點主動和主節點斷開連接:slaveof no one,這個時候從節點晉升為主節點
- 主節點掛了:從節點不會晉升為主節點,必須通過人工干預的方法,恢復主節點
這里有aof文件,這個文件是redis服務器重啟的時候,需要加載的
在上文介紹中,我們三個redis服務器共用的是一個aof文件,這是錯誤的從節點是通過手動啟動的方式運行的。 此時 root 用戶下啟動redis 服務器,于是生成的 aof 文件也就是root用戶的文件。
通過service redis-server start啟動的redis服務器,是通過redis這樣的用戶來啟動的,redis server 需要按照可讀可寫的方式打開這個 aof 文件,而這個文件對于 root 之外的用戶只有讀權限,因此 service redis-server start 啟動的redis 服務器無法打開這個文件,就啟動失敗了。
解決方法:
- 把三個不同的redis服務器生成的文件區分開
- 把三個redis服務器的工作目錄區分開(修改配置文件中的dir選項)
這里采用第二種方案演示:
- 停止所有redis服務器
- 刪除之前工作目錄下已經生成的aof文件,或者chown更改權限
- 給從節點創建出新的目錄,用來作為從節點的工作目錄
vim slave1.conf和slave2.conf修改dir選項為/root/redis-conf