Eureka作為注冊中心想必大家都不陌生了,注冊中心簡單來說,其實就是各個服務將自己的IP和端口號這些信息存放到注冊中心里,形成一個注冊表,當服務間調用的時候,調用方就能從注冊中心的注冊表里面獲取到要調用服務的具體IP和端口號,就可以請求那個服務了
Eureka的注冊表拉取機制分為了兩種,第一種是第一次拉取服務注冊表的時候,此時需要全量拉取注冊表,將所有服務的注冊表信息全部存放起來,第二種是每隔30秒,增量拉取服務注冊表
在eureka client拉取注冊表的時候,就會用到所謂的多級緩存機制,多級緩存機制中有兩個緩存,一個叫只讀緩存ReadOnlyCacheMap,一個叫讀寫緩存ReadWriteCacheMap。eureka client拉取注冊表的時候,會先從ReadOnlyCacheMap中去獲取注冊表數據,如果獲取不到的話再去ReadWriteCacheMap中找,如果還是找不到的話,那就只能重新從注冊表中拉取了
ReadOnlyCacheMap就是一個普通的ConcurrentHashMap,而ReadWriteCacheMap是guava cache(guava cache推薦這個文章:https://www.cnblogs.com/fnlingnzb-learner/p/11022152.html),如果ReadWriteCacheMap讀不到數據,就會通過ClassLoader的load方法直接從注冊表獲取數據再返回
多級緩存機制有多種過期策略
- 主動過期:當服務實例發生注冊、下線、故障的時候,ReadWriteCacheMap中所有的緩存過期掉
- 定時過期:readWriteCacheMap在構建的時候,指定了一個自動過期的時間,默認值就是180秒,所以你往readWriteCacheMap中放入一個數據,180秒過后,就將這個數據給他過期了
- 被動過期:默認是每隔30秒,執行一個定時調度的線程任務,對readOnlyCacheMap和readWriteCacheMap中的數據進行一個比對,如果兩塊數據是不一致的,那么就將readWriteCacheMap中的數據放到readOnlyCacheMap中來
通過過期的機制,可以發現一個問題,就是如果ReadWriteCacheMap發生了主動過期或定時過期,此時里面的緩存就被清空或部分被過期了,但是在此之前readOnlyCacheMap剛執行了被動過期,發現兩個緩存是一致的,就會接着使用里面的緩存數據
所以可能會存在30秒的時間,readOnlyCacheMap和ReadWriteCacheMap的數據不一致
服務注冊表的全量拉取很好理解,就是第一次的時候,從注冊表全量拉取注冊表到eureka client,后面的話就是增量拉取了
增量拉取注冊表的實現借助了一個ConcurrentLinkedQueue類型的變量recentlyChangedQueue,通過名稱我們就能知道這個變量的含義,最近改變的隊列,默認情況下recentlyChangedQueue里面存放的是180秒內修改的服務實例信息,后台會有一個定時任務來維護recentlyChangedQueue,只有最近180秒內有變更的服務實例才會在里面
在增量拉取注冊表時,會將本地的注冊表和recentlyChangedQueue中的服務實例進行一個合並,將有變化的服務實例信息進行一個修改,保證本地的服務注冊表信息和eureka server的服務注冊表一致
在獲取增量注冊表信息的時候,同時獲取了一個eureka server全量注冊表的hash值,這個又是干什么用的呢?在eureka client增量同步注冊表完成之后,也會計算一個hash值,然后將自己計算出來的這個hash值和eureka server全量注冊表的hash值進行比對,如果是一致的,說明增量數據同步沒問題,反之則說了增量數據同步出現了不一致,那么就會重新從eureka server全量拉取一份最新的服務注冊表