摘要: 原創出處 http://www.iocoder.cn/Eureka/instance-registry-read-write-lock/ 「芋道源碼」歡迎轉載,保留摘要,謝謝!
1. 概述
本文主要分享 Eureka 註冊中心的那把讀寫鎖,讓我瘙癢難耐,卻不得其解。在某次意外的摳腳的一刻( 筆者不抽菸,如果抽菸的話,此處應該就不是摳腳了 ),突然頓悟,爽,這好比… 比喻有點猥瑣,筆者就省略 100 字。
不瞎比比,上代碼:
|
推薦 Spring Cloud 書籍:
- 請支持正版。下載盜版,等於主動編寫低級 BUG 。
- 程序猿DD —— 《Spring Cloud微服務實戰》
- 周立 —— 《Spring Cloud與Docker微服務架構實戰》
- 兩書齊買,京東包郵。
2. 讀寫鎖
我們把設計到讀寫鎖的方法整理如下:
方法 | 讀鎖 | 寫鎖 | 不使用 |
---|---|---|---|
#register(...) |
√ | ||
#cancel(...) |
√ | ||
#evict(...) |
√ | ||
#renew(...) |
√ | ||
#statusUpdate(...) |
√ | ||
#deleteStatusOverride(...) |
√ | ||
#getApplicationDeltasFromMultipleRegions(...) |
√ | ||
#getApplicationsFromMultipleRegions(...) |
√ |
是否看到這讀寫感到几絲詭異的味道?OK,我們把問題梳理如下:
- A. 爲什麼
#register(...)
/#cancel(...)
/#evict(...)
/#statusUpdate(...)
/#deleteStatusOverride(...)
等寫操作使用讀鎖 - B. 爲什麼
#renew(...)
寫操作不使用鎖 - C. 爲什麼
#getApplicationDeltasFromMultipleRegions(...)
讀操作使用寫鎖 - D. 爲什麼
getApplicationsFromMultipleRegions(...)
讀操作不使用鎖
先解釋 A + C :
我們來回想下,在 Eureka 應用集合一致性哈希碼的公式:appsHashCode = ${status}_${count}_
。( 不瞭解的同學可以加載下 《Eureka 源碼解析 —— 應用實例註冊發現(七)之增量獲取》「 2. 應用集合一致性哈希碼 」 )
應用實例的數量和狀態都會影響哈希碼的計算結果。也就是說,上述前六個( 包括不使用鎖的 #renew(...)
方法 )方法的調用都會影響哈希碼。
我們把目光移向唯一使用寫鎖的 #getApplicationDeltasFromMultipleRegions(...)
方法,該方法執行過程中,需要保證 recentlyChangedQueue
和 registry
共享變量的應用實例的狀態一致,不然返回的增量應用實例集合的狀態是不準確的。此時能夠達到該效果,必須讓 #getApplicationDeltasFromMultipleRegions(...)
和前六個方法互斥。方案如下:
- a. 全部
synchronized
- b.
#getApplicationDeltasFromMultipleRegions(...)
使用讀鎖,前六個方法使用寫鎖 - c.
#getApplicationDeltasFromMultipleRegions(...)
使用寫鎖,前六個方法使用讀鎖
Eureka 選擇了方案c,原因如下:
- a. 性能太差
- b. 前六個方法使用寫鎖,勢必衝突太大,雖然讀肯定比寫多。
- c.
#getApplicationDeltasFromMultipleRegions(...)
使用寫鎖,配合 ResponseCache ,即減少了寫鎖使用的頻率,每次緩存過期才使用,又避免了前六個方法因爲方案b中的寫鎖導致互斥。( 不瞭解 ResponseCache 的同學可以加載下 《Eureka 源碼解析 —— 應用實例註冊發現(六)之全量獲取》「 3.2 響應緩存 ResponseCache 」 )
再解釋 D
#getApplicationsFromMultipleRegions(...)
方法的邏輯,只依賴 registry
共享變量,不存在應用實例的狀態一致的困擾,所以不使用鎖。
最後解釋 B
#renew(...)
方法的邏輯,雖然會影響應用實例的狀態,但是是極小概率,考慮到它調用的比較頻繁,比起因爲鎖給這個方法帶來的性能降低,不如返回的結果暫時不夠準確。( 想了解極小概率發生原因的同學可以加載 《Eureka 源碼解析 —— 應用實例註冊發現(八)之覆蓋狀態》「 4.3 續租場景 」 )
TODO [0029] 讀寫鎖
筆者路上突然又想了問題,可能不是上述原因,可能和 ResponseCache 有關係,參見 #invalidateCache(...)
方法的每次調用。也就是說,這個讀寫鎖是針對 ResponseCache 的讀寫鎖。
666. 彩蛋
開森 !
本來以爲需要跟 Eureka 官方提交 issue 提問,並且做好了獲得不到答案的準備,結果無意中的摳腳( 請允許我熱愛摳腳給我帶來的靈感 )解答了自己的疑惑。
歲月是把糾結而又萌萌噠的鎖,你不知道你的困擾,哪天不經意的被打開。
願大喜大悲,不枉僅知的這一生。