1. 程式人生 > 資料庫 >Redis設計與實現(十四)複製

Redis設計與實現(十四)複製

在Redis中,使用者可以通過SLAVEOF命令或者slaveof選項讓一個redis伺服器去複製另外一個伺服器的資料,這個複製是所有的庫。

在執行SLAVEOF的時候,從伺服器會向主伺服器傳送一個SYNC命令,主伺服器收到SYNC命令之後會進行BGSAVE命令(也就是生一個子程序進行RDB操作),然後生成完RDB之後將對應的東西重新返回給從伺服器,從伺服器進行載入。那麼從伺服器就可以和主伺服器一樣得到某一時刻的同步,如果在生成RDB的時候,主伺服器依然在進行命令的處理,那麼主伺服器就會將這些命令傳送給從伺服器。完成最新時刻的同步,之後的時間內一旦主伺服器收到Command,就會給從伺服器也傳送一份(也就是命令傳播)。

 

 在2.8之前的Redis對於主從複製的功能有個缺陷就是,如果是初次啟動的Redis從伺服器進行SLAVEOF命令是正常的,邏輯上也是沒問題的,但是如果是斷線後的重新連線,如果依然是進行的SLAVEOF,那麼效率就相對比較低下,問題的來源在於,主伺服器執行BGSAVE的時候,然後生成了子程序,但是依然會佔用很多資源,同時進行傳輸的時候會有很多的頻寬的損失。雖然這一操作是一個看起來很完善的操作,但是問題在於因為強一致性損失了效能。

 

 所以在2.8之後,redis是使用了PSYNC代替了之前的SYNC操作,PSYNC操作具有完成重同步和部分重同步這兩種操作,簡單的收完全重同步是和之前的SYNC一樣的。部分重同步這個就是針對斷線後的重連線進行的,這邊需要思考的是(是不是斷線後的所有情況都滿足這個,以及如何準確的判斷從伺服器斷線的節點),假設有個場景,主伺服器每秒百萬次寫操作,從伺服器每秒十萬次讀操作。從伺服器每斷開一秒都會造成和主伺服器百萬次的指令之差,那麼主伺服器如何對從伺服器的斷開連線進行準確判斷的呢(心跳機制是肯定的)。

 

 部分重同步由以下三個功能組成:主伺服器的複製偏移量和從伺服器的複製偏移量;主伺服器的複製積壓緩衝區;伺服器的執行ID

主伺服器和從伺服器的複製偏移量很好理解,就是伺服器內每次接收到資料,進行累加,通過這個屬性進行對比就可以很輕鬆知道伺服器是否處於一致狀態了。

 

 複製積壓緩衝區是一個FIFO的佇列。預設大小是1MB,當主伺服器進行命令傳播的時候,不光會發送給從伺服器,也會填入複製積壓緩衝區。

 

 因此,主伺服器的複製積壓緩衝區,會儲存著最近傳播的命令。並且記錄下對應的偏移量。

 

 如果複製積壓緩衝區中儲存這對應的指令,那麼就會發送斷線的從伺服器,已經主伺服器在這一時間完成了太多了command導致複製快取積壓區裡面的資料已經被去除了,那麼就只能進行完全重同步了。

 

 伺服器ID這個就不用說了,是用來標識伺服器的。

 

PSYNC指令的實現:

1.如果從伺服器沒有進行過和主伺服器之間的連線,那麼在輸入SLAVEOF XXX.XXX.XX.XX:XXX的時候,實際上會發送一個PSYNC ? -1的command,作用是為了進行一次完全同步,也就是主伺服器進行一次RDB(是否每個從伺服器傳送過來SLAVEOF 都需要進行一次RDB?)

2.如果進行過和主伺服器的完全同步,那麼就會發送PSYNC <runid> <offset>這個指令,runid表示上次和主伺服器進行完全同步時候留下的標識,offset表示偏移量。

主伺服器收到command之後會返回命令有三種:

1.+FULLRESYNC <runid> <offset>這個表示需要進行一次完全同步,runid需要你存起來,下次進行不完全同步時候傳給我,offset表示偏移量。

2.+CONTINUE 表示會進行部分重同步

3.+ERR 則表示主伺服器的版本低於2.8,只能接受SYNCcommand。

 

 

舉例2.8之後的redis實現複製的詳細步驟

 

 在最後會進行心跳機制的重複實現,保證檢查命令丟失情況,網路情況,以及min-slave(防止不安全的情況).