K8s client-go中,源生自帶了一個leader庫,便于實現分布式時間鎖。
以K8s原生的controller-manager組件為例,當有三臺master機器時,默認會運行三個controller-manager實例,但只有一個在干活,另外兩個處于備用狀態。而這個功能的實現,就依賴于分布式時間鎖。
所有相關配置如下圖所示:
鎖的持有者,會每隔retryPeriod更新鎖的有效期,表示它一直在持有這把鎖。
特別說明下兩個參數:
一. leaseTimeout
舉個例子:現在有個房間,我要求當有人進入房間時,下一個人至少等待1小時才可進入房間。這時,我們可以將leaseTimeout設置為1小時,每當有人進入房間,則將房門上的時候改為當前時間。下一個人準備進入時,必須檢查房門上的時間距離當前時間超過leaseTimeout。
之所以要這樣設計,是因為在分布式情況下,只有程序活著的時候才可以要求它干什么,而一旦它異常了,它就失控了。而為了防止在它異常時,其它活著的程序可以正常接替它,所以就約定了leaseTimeout,一旦超過這個時間,則直接認定它異常,可以接管。
二. renewDeadline
上面的約定,無法防止腦裂。因為鎖持有者在leaseTimeout中未更新鎖,并不代表它已經掛了,它可能只是因為其它原因無法更新鎖,或者程序夯住了,之后它可能再恢復。而如果它在別人接替它后,原持有者再恢復運行,則會導致腦裂,為了防止這種情況發生,針對鎖持有者就設置了renewDeadline
如果鎖持有者如果無法在renewDeadline時間內完成鎖的更新,則要求鎖持有者強制釋放鎖,程序退出。
所以renewDeadline必須比leaseTimeout小
上面流程很清晰,下面單獨詳細講下:
嘗試獲取鎖并更新鎖
從上面獲取鎖流程,除了第一次創建鎖之外,選舉的關鍵就是觀察時間: observedTime
id1異常情況
id1網絡異常無法更新鎖
從時序圖中可看出來,監聽時間的必要性。所有的flower(待接替者)都必須更新本地監聽時間,必需保證在renewDeadline時間中,鎖未發生任何變化,否則就需要再重新選舉。
當然,還有一種極端情況:兩個flower同時發現鎖未發生任何變化,同時嘗試去獲取鎖,這個時候就需要用到etcd的resourceVersion機制:在update時需要上送查詢時的resourceVersion,表示在這過程中該資源未發生過其它更新。
原理就類似sql的select for update –> 查詢時鎖定記錄。在這種情況下,etcd會保證先更新的能更新成功,后更新的會失敗。這樣就保證這種極端情況不會腦裂。
服務電話: 400-678-1800 (周??周五 09:00-18:00)
商務合作: 0571-87770835
市場反饋: marketing@woqutech.com
地址: 杭州市濱江區濱安路1190號智匯中?A座1101室