在使用Eureka做注冊中心時挫掏,我平時遇到的最不爽問題,就是無法做到實時上下線秩命。比如尉共,我服務已經正常下線了,為什么上游還能調通弃锐?我服務已經上線了袄友,為什么還有等"很久"才能真正被其他服務所"發(fā)現(xiàn)"?其實這些都是從Eureka到Client再到Ribbion這條鏈路中的逐級緩存造成的霹菊。
Eureka為什么要使用緩存
比如剧蚣,對于Eureka來說,Eureka Client獲取注冊更新信息時,Eureka Server返回的數(shù)據(jù)其實是從一個默認每30s才更新的緩存獲取的券敌。也就是說,如果你服務下了一個柳洋,即使client是在服務下線之后發(fā)請求查詢的注冊列表待诅,那這次請求也不會包括服務下線的信息。那么Eureka為什么要搞cache而不是實時的返回注冊信息呢熊镣?我個人推測了一下卑雁,應該是為了在訪問注冊數(shù)據(jù)結構時盡量少加鎖,從而提升單次請求時的性能绪囱。如果沒有這層cache, 那么對于服務注冊表這個數(shù)據(jù)結構來說测蹲,就會存在并發(fā)讀寫的情況,那就避免不了加鎖保護鬼吵。如果有cache, 是可以做到完全不加鎖的扣甲。想一下,對于微服務架構來說齿椅,特點就是每個服務較輕琉挖,但服務數(shù)量較多。如果每個服務都定時請求eureka更新注冊信息的話涣脚,對于Eureka Server來說示辈,確實是可能會造成嚴重的鎖競爭的。除了這個responseCache外遣蚀,Eureka對于無心跳服務的清理也是默認每60s執(zhí)行一次的矾麻,也就是說對于異常下線的服務(沒有主動取消注冊,而是中斷了心跳)芭梯,在Eureka Server端最大會有長達 60s + 30s * 3 = 150s的延遲险耀。這里的30s * 3 是3個心跳的周期。
Eureka Client的緩存
Eureka Client默認會對注冊信息做30s緩存 玖喘,這個很好理解 胰耗,因為我們當然不希望每次RPC都要重新查一次注冊表,這是很浪費的芒涡。?這是常規(guī)操作柴灯,無可厚非。
Ribbon的緩存
這就有點詭異了费尽。Ribbon向上對接Eureka Client, 向下對接實現(xiàn)發(fā)起HTTP請求的客戶端赠群。ribbon自身也是有30s緩存的,即ribbon會每30s向Eureka Client那里索要注冊信息旱幼,注意是Eureka Client而不是Eureka Server查描,這樣就更加劇了整個系統(tǒng)對服務上下線感知的延遲。我認為Ribbon這樣設計,原因是考慮到了其上游不僅僅是Eureka Client, 還可能是配置文件冬三,或者以編程的方式輸入的注冊列表匀油,而這些查詢是有可能比較耗時的。Ribbon為了兼容這些情況勾笆,不得不添加了緩存敌蚜。
實時上下線思路
只能用消息中間件了。新做一個上下線管理服務窝爪,提供HTTP接口來上下線指定服務弛车,當指定要下線A服務時,先向Eureka發(fā)請求蒲每,將此服務下所有的實例都刪掉纷跛,然后再向kafka類似這樣的消息系統(tǒng)中發(fā)一條消息,所有的微服務都要監(jiān)聽此消息隊列邀杏。
服務收到下線消息時贫奠,將指定服務從本地Ribbon服務列表中刪除。這里Ribbon的 Loadbalancer提供了markServerDown()方法可以使用望蜡,還是容易實現(xiàn)的叮阅。
服務收到上線消息時,需要將服務信息添加到Ribbon中泣特,Ribbon雖然也提供了對應的方法浩姥,但是參數(shù)較為復雜,還需要研究一下状您。
這些功能可以直接打包成starter, 寫好以后各服務直接引用即可勒叠。
2、Eureka Server端優(yōu)秀的多級緩存機制
? ?eureka為了避免同時讀寫內存數(shù)據(jù)結構造成的并發(fā)沖突問題采用了多級緩存的機制:
在拉取注冊表時會首從readonlyCacheMap緩存里查找膏孟,如果沒有再從readWriteCacheMap查找眯分,要是還沒有找到就直接從內存找。 當注冊表發(fā)生改變時柒桑,直接修改內存中的注冊表同時會過濾掉readWriteCacheMap弊决,但readonlyCacheMap不會進行過濾還可以訪問,當?shù)竭_30秒過后后臺線程發(fā)現(xiàn)readWriteCacheMap被清空了魁淳,同時也會清空readonlyCacheMap飘诗。當下個請求進行訪問readonlyCacheMap和readWriteCacheMap會重新從最新的內存注冊表過更新數(shù)據(jù),又達到了一致性界逛。
總結:Eureka同時通過純內存的注冊表昆稿,保證了所有的請求都可以在內存處理,確保了極高的性能息拜,另外多級緩存機制溉潭,確保了不會針對內存數(shù)據(jù)結構發(fā)生頻繁的讀寫并發(fā)沖突操作净响,進一步提升性能。
原文鏈接:https://blog.csdn.net/neosmith/article/details/90213156