閱讀140 返回首頁    go 微軟 go Office


redis slaveof自己會發生什麼

向2.8版本redis發送slaveof,將自己變成自己的slave(簡稱slaveof self)是會返回+OK的,因為響應slaveof命令時,隻是設置下master,接下來的同步都是異步進行的。

127.0.0.1:6379> set key value
OK
127.0.0.1:6379> slaveof 127.0.0.1 6379
OK
127.0.0.1:6379> get key
"value"
(1.03s)
127.0.0.1:6379> get key
"value"
(7.95s)

slaveof self之後,發現redis仍然是可以服務的,但請求響應慢了很多,一個請求通常持續好幾秒鍾,為什麼會這樣?

step1. 當redis接收到slaveof後,將masterhost設置為自己,然後返回OK。

step2. redis在後台建立到master的連接,這條連接的兩端都是這個redis自身,兩端分別稱為master、slave

step3. 連接建立後,slave調用syncWithMaster與master建立同步

step4. slave向master異步發送PING,master回複PONG

step5. slave向master同步發送REPLCONF,調用sendSynchronousCommand,這裏會阻塞的等待5s,直到超時;而由於redis是單線程,此時請求發送給master(實際上是自己),而master又阻塞在這個請求上,所以最終導致REPLCONF一定會超時,slave日誌裏會打印

Master does not understand REPLCONF listening-port: -Reading from master: Connection timed out

step6. slave同步發送PSYNC命令給master,同樣因為自己正阻塞等待,最後這個請求也一定會超時,日誌裏會打印

Unexpected reply to PSYNC from master: -Reading from master: Connection timed out

step7. slave將讀事件處理handler設置為readSyncBulkPayload(6超時,slave上認為沒有錯誤,個人覺得這裏的實現是有問題的),然後進入下一次事件循環,此時redis作為master收到了5、6裏自己發出的請求,回複了+OK;讀事件接下來會觸發slave執行readSyncBulkPayload,從master讀取rdb文件的長度,而實際讀到的是+OK,於是認為協議錯了,就關閉了到master的連接,日誌裏會打印

protocol from MASTER, the first byte is not '$' (we received '+OK'), are you sure the host and port are right?

redis會不斷重複1-7的步驟,當接受到正常的請求時,如果redis剛好阻塞在同步發送REPLCONF、PSYNC(兩個超時各5s,共10s)的過程中,則需要等待這些請求超時,redis下一次進入事件循環才處理請求,所以用戶看到redis的請求延時很大(0-10s不等)。

slaveof self會使redis進入循環嚐試主備同步的狀態,對服務影響非常大,所以運維redis時千萬得小心。

最後更新:2017-04-01 13:37:10

  上一篇:go nginx內部鎖的實現
  下一篇:go 在Linux上編譯iOS程序