redis4.0出現了很多新的特性,刪除鍵值unlink,slowlog記錄來源ip。內存統計信息等。其中一個重要的同步祭祀是Psync2。psync2主要讓redis在從實例重啟和主實例故障切換場景下,也能使用部分重新同步。在redis故障切換,新增從庫,網絡波動。都可以有效的避免網絡風暴。但也存在一個問題。從節點的寫入是不會同步給下一級從節點的。如 A>B>C 在B執行set test xxxx 。C是接收不到key test的。同步信息必須是來源於最根據的master節點。
這與psync2的實現有關:
master_replid :長度為41個字節的字符串。每個實例都有。如果是主節點,則標志這個節點的自身id。如果是從節點。則master_replid 是起最終主節點的master_replid 。
master_replid2:用於存在該節點上一次連接主實例的實例master_replid。
有復制鏈A(100.100)>B(100.88)>C (1.37):
A echo "info Replication" | redis-cli -h 192.168.100.100 -p 6013
B
C
此時 B C 的master_replid 都來源於 A 的master_replid:28ab33a841d0b1db7d0586b120e213970bed2261 。在C 只接收來自於A的寫入。 B的寫入不能同步到C 。如下:
如果B slaveof no one 提升B 為主。復制鏈變成了B>C B是根節點。此時B寫入C可以正常接收。注意看master_replid
B
C
B生成了新的master_replid:1014ea08c4c84cd51cccaa7c9c723c067dcd7b06。並且其從節點的master_replid 變為B 的master_replid 1014ea08c4c84cd51cccaa7c9c723c067dcd7b06 。原來的 A的master_replid 歸檔進了master_replid2。
4.0在整個復制集群中通過master_replid 和master_repl_offset 使得每個從節點的偏移量都是相對於最原始的主節點(無論串型還是星型)。這樣復制從節點的切換主節點,不需要再進行全同步。只需部分同步。A>B>C 變為 A>B A>C 。或者B>A B>A>C
或者 B>A (B slave no one后 。A 根據自身master_replid向B 請求部分同步 。B 的master_replid2存放了Amaster_replid 。所以可以部分同步 )
邏輯是。每次slaveof 本節點會拿自身的master_replid master_repl_offset 去尋找目標節點的 master_replid master_replid2 和offset。如果匹配到則可增量同步。
重啟從節點的時候。一定要把slaveof寫入到配置文件中再重啟。這樣才可以部分同步。如果啟動完節點再自行slaveof則需要全同步。
同樣的,在擴展從節點的時候也可以先在主節點dump一份數據。然后rsync到別的機器。在配置文件配置好slaveof。啟動redis這樣可以部分同步,避免網絡風暴。
但主節點A重啟會導致 master_replid 變動。最終導致從節點重新全同步。是否有辦法保持master_replid不變???
除了本身是master節點。slave節點執行slave one 導致master_replid 更新。且 master_replid2 不會保留自身生成的master_replid 。如slaveof no one之后再slave xx xx 。master_replid2 會是空的。
A>B>C 。B執行slave no one 不會導致C全同步,此時B是master。但是B 再slaveof xx xx (那么是slaveof A ) 都會導致C重新全同步。因為B master_replid2 保留自身slave no one后生成的master_replid 。C在同步的時候在B中找不到replid