最近工作中開始搭建工程,發現一個很迷惑的地方 DS Replicas。 之前接觸Eureka也只是簡單搭建。
現象描述:
eureka在k8s環境起了兩台。回家后本地搭建配置文件如下:application-peerA/peerB.yml,外加本地host修改。
application-peerA.yml
EUREKA_INSTANCE_HOSTNAME: peerA
EUREKA_SERVER: http://peerB:8081/eureka/,http://peerA:8080/eureka/
PORT: 8080
server:
port: ${PORT}
spring:
application:
name: eureka-server
eureka:
server:
enable-self-preservation: false
use-read-only-response-cache: false
eviction-interval-timer-in-ms: 5000
client:
registry-fetch-interval-seconds: 5
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: ${EUREKA_SERVER:http://127.0.0.1:${server.port}/eureka/}
instance:
hostname: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 10
instance-id: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}:${server.port}@${random.long(1000000,9999999)}
application-peerB.yml
EUREKA_INSTANCE_HOSTNAME: peerB
EUREKA_SERVER: http://peerA:8080/eureka/,http://peerB:8081/eureka/
PORT: 8081
server:
port: ${PORT}
spring:
application:
name: eureka-server
eureka:
server:
#關閉自我保護
enable-self-preservation: false
use-read-only-response-cache: false
#設置自動清理時間
eviction-interval-timer-in-ms: 5000
client:
registry-fetch-interval-seconds: 5
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: ${EUREKA_SERVER:http://127.0.0.1:${server.port}/eureka/}
instance:
hostname: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 10
instance-id: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}:${server.port}@${random.long(1000000,9999999)}
本地host修改如下。
127.0.0.1 peerB
127.0.0.1 peerA
兩台服務啟動效果如下,只看到peerA頁面下DS Replicas只有peerB, peerB下的DS只有peerA。
線上環境中兩台下面都是這樣的。peerA和peerB。
現象清楚了,就是本地模擬環境上k8s兩台服務時候, DS Replicas展示不一樣。
探究現象背后的原因
因為對SpringBoot包括Eureka沒有特別深入學習過,所以只能自己嘗試看代碼發現問題。
localhost:8080頁面是怎么渲染出來的
1.在IDEA的幫助下找到了這個接口對應的handler,可以發現兩個結論:1. EurekaController就是我們要找的;2.可以通過eureka.dashboard.path配置修改eureka dashboard的地址,默認是/。
2.然后就在該Controller中驗證了猜想。可以得出結論:方法返回值為String,應該是使了JSP或Freemarker等模板。
3.通過IDEA的幫助,定位Class所在包,如左圖。可以得出結論:1.確實是使用了freemarker模板;2.status.ftlh就是我們要找的首頁模板了。
4.發現status.ftlh中沒有DS Replicas關鍵字,在navbar.ftlh中找到的。可以得出結論:replicas這個就是頁面渲染使用到的數據,是一個列表。
5.於是返回RequestMapping中查找replicas是怎么填充的。可以猜測:PeerEurekaNode這個對象有幾個決定頁面的DS Replicas。
6.到這里也只是發現了DS Replicas和PeerEurekaNode有很大關系,具體是什么還完全沒頭緒。
PeerEurekaNode是啥?
上一步分析到這里。通過分析調用關系,發現:serverContext是DefaultEurekaServerContext,PeerEurekaNodes具體是RefreshablePeerEurekaNodes。下面只要分析RefreshablePeerEurekaNodes的getPeerNodesView方法即可。
1.RefreshablePeerEurekaNodes繼承自PeerEurekaNodes,其內部維護一個列表,PeerEurekaNode的集合。 首頁用到的就是這個列表的副本。這個屬性只有在updatePeerEurekaNodes方法中有修改操作。
2.IDEA中查看上述方法只有如下兩處調用:第二處可以理解為是環境刷新時候調用,第一處才是最常調用的地方。
3.start方法是DefaultEurekaServerContext對象生成完畢后調用,只調用一次。start方法內部用單個專門線程去定期調用一次updatePeerEurekaNodes方法,頻率為固定10分鍾。
4. updatePeerEurekaNodes方法入參為resolvePeerUrls,解析伙伴的URL。其中isThisMyUrl會比較URL的host與本機host相比較,如果相同就會去除掉。
5. 繼續研究下去發現了InstanceInfo、EurekaInstanceConfigBean、InetUtils、findFirstNonLoopbackHostInfo, 大概明白了主要是k8s環境中eureka的網卡信息上查找到的主機名 和 yml中`eureka.instance.hostname` 天然不一樣,所以就導致了DS出現多個結果。 這點在k8s POD中通過 ip addr得到了證實,涉及敏感數據、IP就不貼圖了。
總結:
小白嘗試着查看了代碼,分析得到了本地啟動的多個eureka中DS不同的原因; 原因是:K8S中eureka是通過statefulset方式部署的,service-url也是用StatefulSet寫法寫的,POD的環境天生和本地不一樣,也算有點收獲吧,再深入的話得不償失了。