http://bboyjing.github.io/2016/12/08/Redis%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E5%85%AB%E3%80%90Redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E3%80%91/
對于高負載應用來說,復制(replication)是不可或缺的一個特性,復制可以讓其他服務器擁有一個不斷地更新的數據副本,從而使得擁有副本數據的服務器可以用于處理客戶端發送的讀請求。關系型數據庫通常會使用一個主服務器(master)向多個從服務器(slave)發送更行,并使用從服務器來處理所有讀請求。Redis也采用了同樣的方法來實現自己的復制特性,并將其用作擴展性能的一種手段。
復制相關配置選項
之前說過,當從服務器連接主服務器時,主服務器會執行BGSAVE操作,因此要求主服務器的快照持久化功能正常。配置slaveof host port選項即可連接主服務器。下面來測試下:
再安裝一個Redis,直接拷貝之前的安裝好的文件夾即可,本人安裝的兩個Redis路徑為/opt/redis-3.2.4、/opt/redis-replication
1 2 3
| cd /opt sudo cp -r redis-3.2.4 redis-replication sudo chmod -R 777 redis-replication
|
修改redis-replication的redis.conf文件,改兩個配置port和slaveof
1 2
| port 6380 slaveof localhost 6379
|
啟動redis-3.2.4
1 2 3 4 5 6 7 8
| cd /opt/redis-3.2.4 ./src/redis-server ./redis.conf //啟動交互式命令行并添加兩個key ./src/redis-cli 127.0.0.1:6379> set key1 hello OK 127.0.0.1:6379> set key2 world OK
|
啟動redis-replication
1 2 3 4 5 6 7 8
| cd /opt/redis-replication ./src/redis-server ./redis.conf //啟動交互式命令行 ./src/redis-cli -h localhost -p 6380 //查看數據,6380端口的Redis服務上也有key1和key2了 localhost:6380> keys * 1) "key2" 2) "key1"
|
測試數據更新推送
1 2 3 4 5 6 7 8
| //主服務添加key3 127.0.0.1:6379> set key3 ! OK //從服務收到數據更新 localhost:6380> keys * 1) "key3" 2) "key2" 3) "key1"
|
對于一個正在運行的Redis服務器,可以發送SLAVEOF no one命令來讓服務器終止復制操作,不再接受主服務器的數據更新;也可以通過發送SLAVEOF host port命令來讓服務器開始復制一個新的主服務器,這個就不測試了,了解下有這個功能。
Redis復制的啟動過程
從服務器連接主服務器時,主服務器會創建一個快照文件并將其發送至從服務器,但這只是主從復制執行過程的其中一步,下面列舉出復制過程中Redis所有的行為:
步驟 | 主服務器操作 | 從服務器操作 |
---|
1 | 等待命令進入 | 連接(或者重連接)主服務器,發送SYNC命令 |
2 | 開始執行BGSAVE,并使用緩沖區記錄BGSAVE之后執行的所有寫命令 | 根據配置選項來決定時繼續使用現在的數據來處理客戶端命令,還是向發送請求的客戶端返回錯誤 |
3 | BGSAVE執行完畢,向從服務器發送快照文件,并在發送期間繼續使用緩沖區記錄杯知行的寫命令 | 丟棄所有舊的數據,開始載入主服務器發來的快照文件 |
4 | 快照文件發送完畢,開始向從服務器發送存儲在緩沖區里面的寫命令 | 完成對快照文件的解釋操作,像往常一樣開始接受命令請求 |
5 | 緩沖區存儲的寫命令發送完畢;從現在開始,沒執行一個寫命令,就像從服務器發送相同的寫命令 | 執行主服務器發來的所有存儲在緩沖區里面的寫命令;從現在開始,接收并執行主服務器傳來的每個寫命令 |
由上述步驟可以看出,有必要給Redis主服務器留30%~45%的內存用于執行BGSAVE命令和創建記錄寫命令的緩沖區。另外,從服務器還有一點需要注意的是,從服務器在進行同步時,會清空自己的所有數據,因為第3步中,從服務器會丟棄所有舊數據。
注:Redis不支持主主復制(master-master replication)lian
當多個從服務器嘗試連接同一個主服務器的時候,就會出現下表所示的兩種情況中的其中一種:
當有新的從服務器連接主服務器時 | 主服務器的操作 |
---|
上述步驟3尚未執行 | 所有從服務器都會接收相同的快照文件和相同的緩沖區寫命令 |
上述步驟3正在執行或者已經執行 | 當主服務器與較早進行連接的從服務器執行完復制所需的5個步驟之后,主服務器會與新連接的從服務器執行一次新的步驟1至步驟5 |
由此可以看出多個從服務器的同步對網絡的開銷挺大的,有可能會影響到主服務器接收寫命令,甚至是與主服務器位于同一網絡中的其他硬件。
主從鏈
上面講到創建多個從服務器可能造成網絡不可用,此時可以使用另外一個解決方案,從服務器擁有自己的從服務器,并由此形成主從鏈(master/slave chaining)。當讀請求的重要性明顯高于寫請求的重要性,并且讀請求的數量需求遠遠超出一臺Redis服務器可以處理的范圍時,用戶就需要添加新的從服務器來處理讀請求,隨著負載不斷上升,主服務器可能會無法快速地更新所有從服務器。為了緩解這個問題,可以創建一個由Redis主/從節點(master/slave node)組成的中間層來分擔主服務器的復制工作,如下圖所示:

按照上圖的樹狀結構,只有3臺從服務器和主服務器通信,其他都向從服務器同步數據,分散了網絡開銷。如果12臺從服務器都向主服務器同步數據的話,想想也覺得有點牽強了。